Compare commits
2 Commits
issue/4426
...
issue/4346
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
367cd61e35 | ||
|
|
8a9f5361a1 |
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
<version>4.2.x-4346-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
<version>4.2.x-4346-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
<version>4.2.x-4346-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
<version>4.2.x-4346-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1571,6 +1571,39 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return newDocument;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object convertToMongoType(@Nullable Object obj, MongoPersistentProperty property) {
|
||||
|
||||
PersistentPropertyAccessor accessor = new MapPersistentPropertyAccessor();
|
||||
accessor.setProperty(property, obj);
|
||||
|
||||
Document newDocument = new Document();
|
||||
DocumentAccessor dbObjectAccessor = new DocumentAccessor(newDocument);
|
||||
|
||||
if (property.isIdProperty() || !property.isWritable()) {
|
||||
return obj;
|
||||
}
|
||||
if (property.isAssociation()) {
|
||||
|
||||
writeAssociation(property.getRequiredAssociation(), accessor, dbObjectAccessor);
|
||||
return dbObjectAccessor.get(property);
|
||||
}
|
||||
|
||||
Object value = obj;
|
||||
|
||||
if (value == null) {
|
||||
if (property.writeNullValues()) {
|
||||
dbObjectAccessor.put(property, null);
|
||||
}
|
||||
} else if (!conversions.isSimpleType(value.getClass())) {
|
||||
writePropertyInternal(value, dbObjectAccessor, property, accessor);
|
||||
} else {
|
||||
writeSimpleInternal(value, newDocument, property, accessor);
|
||||
}
|
||||
return dbObjectAccessor.get(property);
|
||||
}
|
||||
|
||||
// TODO: hide in 4.0
|
||||
public List<Object> maybeConvertList(Iterable<?> source, @Nullable TypeInformation<?> typeInformation) {
|
||||
|
||||
|
||||
@@ -42,12 +42,15 @@ import org.springframework.data.convert.PropertyValueConverter;
|
||||
import org.springframework.data.convert.PropertyValueConverterFactory;
|
||||
import org.springframework.data.convert.PropertyValueConverterRegistrar;
|
||||
import org.springframework.data.convert.SimplePropertyValueConversions;
|
||||
import org.springframework.data.convert.ValueConversionContext;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Value object to capture custom conversion. {@link MongoCustomConversions} also act as factory for
|
||||
@@ -331,9 +334,40 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus
|
||||
svc.init();
|
||||
}
|
||||
|
||||
// Move to data-commons?
|
||||
PropertyValueConversions pvc = new PropertyValueConversions() {
|
||||
|
||||
@Override
|
||||
public boolean hasValueConverter(PersistentProperty<?> property) {
|
||||
return propertyValueConversions.hasValueConverter(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <DV, SV, P extends PersistentProperty<P>, VCC extends ValueConversionContext<P>> PropertyValueConverter<DV, SV, VCC> getValueConverter(
|
||||
P property) {
|
||||
|
||||
return new PropertyValueConverter<DV, SV, VCC>() {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DV read(SV value, VCC context) {
|
||||
return (DV) propertyValueConversions.getValueConverter(property).read(value, context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SV write(DV value, VCC context) {
|
||||
if (ClassUtils.isAssignable(property.getType(), value.getClass())) {
|
||||
return (SV) propertyValueConversions.getValueConverter(property).write(value, context);
|
||||
}
|
||||
return (SV) value;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
if (!useNativeDriverJavaTimeCodecs) {
|
||||
return new ConverterConfiguration(STORE_CONVERSIONS, this.customConverters, convertiblePair -> true,
|
||||
this.propertyValueConversions);
|
||||
return new ConverterConfiguration(STORE_CONVERSIONS, this.customConverters, convertiblePair -> true, pvc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -358,7 +392,7 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus
|
||||
}
|
||||
|
||||
return true;
|
||||
}, this.propertyValueConversions);
|
||||
}, pvc);
|
||||
}
|
||||
|
||||
private enum DateToUtcLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
|
||||
|
||||
@@ -59,6 +59,11 @@ public interface MongoWriter<T> extends EntityWriter<T, Bson> {
|
||||
@Nullable
|
||||
Object convertToMongoType(@Nullable Object obj, @Nullable TypeInformation<?> typeInformation);
|
||||
|
||||
@Nullable
|
||||
default Object convertToMongoType(@Nullable Object obj, MongoPersistentProperty property) {
|
||||
return convertToMongoType(obj, property.getTypeInformation());
|
||||
}
|
||||
|
||||
default Object convertToMongoType(@Nullable Object obj, MongoPersistentEntity<?> entity) {
|
||||
return convertToMongoType(obj, entity.getTypeInformation());
|
||||
}
|
||||
|
||||
@@ -36,9 +36,11 @@ import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Custom {@link ParameterAccessor} that uses a {@link MongoWriter} to serialize parameters into Mongo format.
|
||||
@@ -91,7 +93,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
}
|
||||
|
||||
public Object getBindableValue(int index) {
|
||||
return getConvertedValue(delegate.getBindableValue(index), null);
|
||||
return getConvertedValue(delegate.getBindableValue(index), (TypeInformation<?>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,6 +131,11 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
return writer.convertToMongoType(value, typeInformation == null ? null : typeInformation.getActualType());
|
||||
}
|
||||
|
||||
|
||||
public Object getConvertedValue(Object value, MongoPersistentProperty property) {
|
||||
return writer.convertToMongoType(value, property);
|
||||
}
|
||||
|
||||
public boolean hasBindableNullValue() {
|
||||
return delegate.hasBindableNullValue();
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(MongoQueryCreator.class);
|
||||
|
||||
private final MongoParameterAccessor accessor;
|
||||
private final ConvertingParameterAccessor accessor;
|
||||
private final MappingContext<?, MongoPersistentProperty> context;
|
||||
private final boolean isGeoNearQuery;
|
||||
|
||||
@@ -345,6 +345,17 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
"Argument for creating $regex pattern for property '%s' must not be null", part.getProperty().getSegment()));
|
||||
}
|
||||
|
||||
try {
|
||||
PersistentPropertyPath<MongoPersistentProperty> persistentPropertyPath = context.getPersistentPropertyPath(part.getProperty());
|
||||
MongoPersistentProperty leafProperty = persistentPropertyPath.getLeafProperty();/// maybe a call back here
|
||||
if (leafProperty != null) {
|
||||
Object convertedValue = accessor.getConvertedValue(value.toString(), leafProperty);
|
||||
return criteria.regex(toLikeRegex(convertedValue.toString(), part), toRegexOptions(part));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
System.err.print(ex);
|
||||
}
|
||||
|
||||
return criteria.regex(toLikeRegex(value.toString(), part), toRegexOptions(part));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
package org.springframework.data.mongodb;
|
||||
|
||||
import org.springframework.data.mongodb.core.convert.MongoConversionContext;
|
||||
import org.springframework.data.mongodb.core.convert.MongoValueConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class ReversingValueConverter implements MongoValueConverter<String, String> {
|
||||
public class ReversingValueConverter implements MongoValueConverter<String, String> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bson.BsonRegularExpression;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.bson.types.Code;
|
||||
import org.bson.types.ObjectId;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.ReversingValueConverter;
|
||||
import org.springframework.data.mongodb.core.DocumentTestUtils;
|
||||
import org.springframework.data.mongodb.core.Person;
|
||||
import org.springframework.data.mongodb.core.aggregation.ComparisonOperators;
|
||||
@@ -1455,6 +1457,15 @@ public class QueryMapperUnitTests {
|
||||
assertThat(mappedObject).isEqualTo(new org.bson.Document("text", "eulav"));
|
||||
}
|
||||
|
||||
@Test // GH-4346
|
||||
void ignoresValueConverterForNonMatchingType() {
|
||||
|
||||
org.bson.Document source = new org.bson.Document("text", new BsonRegularExpression("value"));
|
||||
org.bson.Document mappedObject = mapper.getMappedObject(source, context.getPersistentEntity(WithPropertyValueConverter.class));
|
||||
|
||||
assertThat(mappedObject).isEqualTo(source);
|
||||
}
|
||||
|
||||
@Test // GH-2750
|
||||
void mapsAggregationExpression() {
|
||||
|
||||
|
||||
@@ -47,9 +47,8 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mongodb.ReversingValueConverter;
|
||||
import org.springframework.data.mongodb.core.DocumentTestUtils;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.UpdateMapper;
|
||||
import org.springframework.data.mongodb.core.mapping.DocumentReference;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
|
||||
@@ -1637,4 +1637,19 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie
|
||||
assertThat(repository.findById(dave.getId()).map(Person::getShippingAddresses))
|
||||
.contains(Collections.singleton(address));
|
||||
}
|
||||
|
||||
@Test // GH-4346
|
||||
@DirtiesState
|
||||
void findCreatingRegexWithValueConverterWorks() {
|
||||
|
||||
Person bart = new Person("bart", "simpson");
|
||||
bart.setNickName("bartman");
|
||||
|
||||
operations.save(bart);
|
||||
|
||||
List<Person> result = repository.findByNickNameContains("artma");
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).getId().equals(bart.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.convert.ValueConverter;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.ReversingValueConverter;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
@@ -78,6 +80,9 @@ public class Person extends Contact {
|
||||
|
||||
@DocumentReference User spiritAnimal;
|
||||
|
||||
@ValueConverter(ReversingValueConverter.class)
|
||||
String nickName;
|
||||
|
||||
int visits;
|
||||
|
||||
public Person() {
|
||||
@@ -325,6 +330,14 @@ public class Person extends Contact {
|
||||
this.spiritAnimal = spiritAnimal;
|
||||
}
|
||||
|
||||
public String getNickName() {
|
||||
return nickName;
|
||||
}
|
||||
|
||||
public void setNickName(String nickName) {
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
|
||||
@@ -465,4 +465,5 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
|
||||
|
||||
List<Person> findBySpiritAnimal(User user);
|
||||
|
||||
List<Person> findByNickNameContains(String nickName);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.convert.ValueConverter;
|
||||
import org.springframework.data.domain.Range;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
import org.springframework.data.geo.Distance;
|
||||
@@ -40,7 +41,9 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.Person;
|
||||
import org.springframework.data.mongodb.core.Venue;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConversionContext;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoValueConverter;
|
||||
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||
@@ -57,6 +60,7 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Unit test for {@link MongoQueryCreator}.
|
||||
@@ -658,6 +662,16 @@ class MongoQueryCreatorUnitTests {
|
||||
assertThat(creator.createQuery()).isEqualTo(query(where("location").nearSphere(point).maxDistance(1000.0D)));
|
||||
}
|
||||
|
||||
@Test // GH-4346
|
||||
void likeQueriesShouldApplyPropertyValueConverterWhenCreatingRegex() {
|
||||
|
||||
PartTree tree = new PartTree("findByTextStartingWith", WithValueConverter.class);
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "spring"), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query).isEqualTo(query(where("text").regex("^gnirps")));
|
||||
}
|
||||
|
||||
interface PersonRepository extends Repository<Person, Long> {
|
||||
|
||||
List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname);
|
||||
@@ -693,4 +707,34 @@ class MongoQueryCreatorUnitTests {
|
||||
|
||||
@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE) Point geo;
|
||||
}
|
||||
|
||||
static class WithValueConverter {
|
||||
|
||||
@ValueConverter(ReversingValueConverter.class)
|
||||
String text;
|
||||
}
|
||||
|
||||
static class ReversingValueConverter implements MongoValueConverter<String, String> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String read(@Nullable String value, MongoConversionContext context) {
|
||||
return reverse(value);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String write(@Nullable String value, MongoConversionContext context) {
|
||||
return reverse(value);
|
||||
}
|
||||
|
||||
private String reverse(String source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new StringBuilder(source).reverse().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
<appender name="no-op" class="ch.qos.logback.core.helpers.NOPAppender" />
|
||||
|
||||
<!--
|
||||
<logger name="org.mongodb.driver.protocol" level="DEBUG" />
|
||||
-->
|
||||
|
||||
<!--
|
||||
<logger name="org.springframework" level="debug" />
|
||||
-->
|
||||
|
||||
Reference in New Issue
Block a user