Browse Source

DATAMONGO-600 - Fixed parameter binding for derived queries on properties using polymorphism.

We need to retain the type in the serialized DBObject in case a derived query binds parameters for properties that use polymorphism as we serialize the object as nested document and this only matches in an all-or-nothing way. So if the type information is missing, we won't see any results.

So we now hand the TypeInformation of the property into the conversion logic and transparently skip the type information removal in case the types differ. Upgraded to Querydsl 2.8.2 as it fixes a bug regarding the APT processing which the test cases would stumble into otherwise.
1.1.x
Oliver Gierke 13 years ago
parent
commit
cfa3e467d1
  1. 2
      spring-data-mongodb/pom.xml
  2. 15
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/AbstractMongoConverter.java
  3. 13
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  4. 15
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoWriter.java
  5. 23
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java
  6. 5
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoOperationsUnitTests.java
  7. 21
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java
  8. 24
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Credentials.java
  9. 4
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java
  10. 8
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java
  11. 25
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/UsernameAndPassword.java
  12. 5
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java

2
spring-data-mongodb/pom.xml

@ -11,7 +11,7 @@
<name>Spring Data MongoDB</name> <name>Spring Data MongoDB</name>
<properties> <properties>
<querydsl.version>2.8.0</querydsl.version> <querydsl.version>2.8.2</querydsl.version>
<cdi.version>1.0</cdi.version> <cdi.version>1.0</cdi.version>
<validation.version>1.0.0.GA</validation.version> <validation.version>1.0.0.GA</validation.version>
<webbeans.version>1.1.3</webbeans.version> <webbeans.version>1.1.3</webbeans.version>

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011 by the original author(s). * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.data.mongodb.core.convert; package org.springframework.data.mongodb.core.convert;
import java.math.BigInteger; import java.math.BigInteger;
@ -33,8 +32,8 @@ import org.springframework.data.mongodb.core.convert.MongoConverters.StringToObj
* Base class for {@link MongoConverter} implementations. Sets up a {@link GenericConversionService} and populates basic * Base class for {@link MongoConverter} implementations. Sets up a {@link GenericConversionService} and populates basic
* converters. Allows registering {@link CustomConversions}. * converters. Allows registering {@link CustomConversions}.
* *
* @author Jon Brisbin <jbrisbin@vmware.com> * @author Jon Brisbin
* @author Oliver Gierke ogierke@vmware.com * @author Oliver Gierke
*/ */
public abstract class AbstractMongoConverter implements MongoConverter, InitializingBean { public abstract class AbstractMongoConverter implements MongoConverter, InitializingBean {
@ -94,6 +93,14 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
conversions.registerConvertersIn(conversionService); conversions.registerConvertersIn(conversionService);
} }
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object)
*/
public Object convertToMongoType(Object obj) {
return convertToMongoType(obj, null);
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.convert.MongoConverter#getConversionService() * @see org.springframework.data.mongodb.core.core.convert.MongoConverter#getConversionService()

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 by the original author(s). * Copyright 2011-2013 by the original author(s).
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -813,8 +813,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return rootList; return rootList;
} }
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object, org.springframework.data.util.TypeInformation)
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Object convertToMongoType(Object obj) { public Object convertToMongoType(Object obj, TypeInformation<?> typeInformation) {
if (obj == null) { if (obj == null) {
return null; return null;
@ -861,9 +865,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
DBObject newDbo = new BasicDBObject(); DBObject newDbo = new BasicDBObject();
this.write(obj, newDbo); this.write(obj, newDbo);
if (typeInformation == null) {
return removeTypeInfoRecursively(newDbo); return removeTypeInfoRecursively(newDbo);
} }
return !obj.getClass().equals(typeInformation.getType()) ? newDbo : removeTypeInfoRecursively(newDbo);
}
public BasicDBList maybeConvertList(Iterable<?> source) { public BasicDBList maybeConvertList(Iterable<?> source) {
BasicDBList newDbl = new BasicDBList(); BasicDBList newDbl = new BasicDBList();
for (Object element : source) { for (Object element : source) {

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2012 the original author or authors. * Copyright 2010-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.convert;
import org.springframework.data.convert.EntityWriter; import org.springframework.data.convert.EntityWriter;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.util.TypeInformation;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import com.mongodb.DBRef; import com.mongodb.DBRef;
@ -35,11 +36,21 @@ public interface MongoWriter<T> extends EntityWriter<T, DBObject> {
* Converts the given object into one Mongo will be able to store natively. If the given object can already be stored * Converts the given object into one Mongo will be able to store natively. If the given object can already be stored
* as is, no conversion will happen. * as is, no conversion will happen.
* *
* @param obj * @param obj can be {@literal null}.
* @return * @return
*/ */
Object convertToMongoType(Object obj); Object convertToMongoType(Object obj);
/**
* Converts the given object into one Mongo will be able to store natively but retains the type information in case
* the given {@link TypeInformation} differs from the given object type.
*
* @param obj can be {@literal null}.
* @param typeInformation can be {@literal null}.
* @return
*/
Object convertToMongoType(Object obj, TypeInformation<?> typeInformation);
/** /**
* Creates a {@link DBRef} to refer to the given object. * Creates a {@link DBRef} to refer to the given object.
* *

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2011 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import org.springframework.data.mongodb.core.geo.Distance;
import org.springframework.data.mongodb.core.geo.Point; import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@ -85,12 +86,12 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
return delegate.getSort(); return delegate.getSort();
} }
/* (non-Javadoc) /*
* @see org.springframework.data.repository.query.ParameterAccessor#getBindableParameter(int) * (non-Javadoc)
* @see org.springframework.data.repository.query.ParameterAccessor#getBindableValue(int)
*/ */
public Object getBindableValue(int index) { public Object getBindableValue(int index) {
return getConvertedValue(delegate.getBindableValue(index), null);
return getConvertedValue(delegate.getBindableValue(index));
} }
/* /*
@ -101,7 +102,8 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
return delegate.getMaxDistance(); return delegate.getMaxDistance();
} }
/* (non-Javadoc) /*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.MongoParameterAccessor#getGeoNearLocation() * @see org.springframework.data.mongodb.repository.MongoParameterAccessor#getGeoNearLocation()
*/ */
public Point getGeoNearLocation() { public Point getGeoNearLocation() {
@ -111,11 +113,12 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
/** /**
* Converts the given value with the underlying {@link MongoWriter}. * Converts the given value with the underlying {@link MongoWriter}.
* *
* @param value * @param value can be {@literal null}.
* @param typeInformation can be {@literal null}.
* @return * @return
*/ */
private Object getConvertedValue(Object value) { private Object getConvertedValue(Object value, TypeInformation<?> typeInformation) {
return writer.convertToMongoType(value); return writer.convertToMongoType(value, typeInformation == null ? null : typeInformation.getActualType());
} }
/* /*
@ -186,7 +189,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
} }
} }
return getConvertedValue(next); return getConvertedValue(next, property.getTypeInformation());
} }
/* /*

5
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoOperationsUnitTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2011 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -34,6 +34,7 @@ import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.util.TypeInformation;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
import com.mongodb.DBObject; import com.mongodb.DBObject;
@ -78,7 +79,7 @@ public abstract class MongoOperationsUnitTests {
return null; return null;
} }
public Object convertToMongoType(Object obj) { public Object convertToMongoType(Object obj, TypeInformation<?> typeInformation) {
return null; return null;
} }

21
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -523,4 +523,23 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
assertThat(result, hasSize(1)); assertThat(result, hasSize(1));
assertThat(result, hasItem(oliver)); assertThat(result, hasItem(oliver));
} }
/**
* @see DATAMONGO-600
*/
@Test
public void readsDocumentsWithNestedPolymorphismCorrectly() {
UsernameAndPassword usernameAndPassword = new UsernameAndPassword();
usernameAndPassword.username = "dave";
usernameAndPassword.password = "btcs";
dave.credentials = usernameAndPassword;
repository.save(dave);
List<Person> result = repository.findByCredentials(usernameAndPassword);
assertThat(result, hasSize(1));
assertThat(result, hasItem(dave));
}
} }

24
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Credentials.java

@ -0,0 +1,24 @@
/*
* 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.repository;
/**
*
* @author Oliver Gierke
*/
public interface Credentials {
}

4
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2011 the original author or authors. * Copyright 2010-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -54,6 +54,8 @@ public class Person extends Contact {
@DBRef @DBRef
User creator; User creator;
Credentials credentials;
public Person() { public Person() {
this(null, null); this(null, null);

8
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2012 the original author or authors. * Copyright 2010-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -192,4 +192,10 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
*/ */
List<Person> findByLastnameNot(String lastname); List<Person> findByLastnameNot(String lastname);
/**
* @see DATAMONGO-600
* @param credentials
* @return
*/
List<Person> findByCredentials(Credentials credentials);
} }

25
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/UsernameAndPassword.java

@ -0,0 +1,25 @@
/*
* 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.repository;
/**
* @author Oliver Gierke
*/
public class UsernameAndPassword implements Credentials {
String username;
String password;
}

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -49,6 +49,7 @@ import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.util.TypeInformation;
/** /**
* Unit test for {@link MongoQueryCreator}. * Unit test for {@link MongoQueryCreator}.
@ -74,7 +75,7 @@ public class MongoQueryCreatorUnitTests {
public Object answer(InvocationOnMock invocation) throws Throwable { public Object answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArguments()[0]; return invocation.getArguments()[0];
} }
}).when(converter).convertToMongoType(any()); }).when(converter).convertToMongoType(any(), Mockito.any(TypeInformation.class));
} }
@Test @Test

Loading…
Cancel
Save