diff --git a/pom.xml b/pom.xml index 41512eaee8..42d29d3933 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1288-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index fd36debedd..b2b9eca9d7 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-mongodb-parent - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1288-SNAPSHOT ../pom.xml @@ -48,7 +48,7 @@ org.springframework.data spring-data-mongodb - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1288-SNAPSHOT diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 28c91bc332..905fe9d556 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1288-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index dfe146ff96..b21d01a90b 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1288-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 628b1ec633..219143daff 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-mongodb-parent - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1288-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java index d782492f50..f7a2471f27 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java @@ -47,6 +47,7 @@ import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToNamedMongoScriptCoverter; import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.NamedMongoScriptToDBObjectConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.NumberToNumberConverterFactory; import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.StringToURLConverter; @@ -122,6 +123,7 @@ public CustomConversions(List converters) { toRegister.add(TermToStringConverter.INSTANCE); toRegister.add(NamedMongoScriptToDBObjectConverter.INSTANCE); toRegister.add(DBObjectToNamedMongoScriptCoverter.INSTANCE); + toRegister.add(NumberToNumberConverterFactory.INSTANCE); toRegister.addAll(JodaTimeConverters.getConvertersToRegister()); toRegister.addAll(GeoConverters.getConvertersToRegister()); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java index dfc796628d..303562d810 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java @@ -19,16 +19,21 @@ import java.math.BigInteger; import java.net.MalformedURLException; import java.net.URL; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import org.bson.types.Code; import org.bson.types.ObjectId; import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.ConditionalConverter; import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterFactory; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; import org.springframework.data.mongodb.core.query.Term; import org.springframework.data.mongodb.core.script.NamedMongoScript; +import org.springframework.util.NumberUtils; import org.springframework.util.StringUtils; import com.mongodb.BasicDBObject; @@ -228,4 +233,50 @@ public DBObject convert(NamedMongoScript source) { return builder.get(); } } + + /** + * {@link ConverterFactory} implementation using {@link NumberUtils} for number conversion and parsing. Additionally + * deals with {@link AtomicInteger} and {@link AtomicLong} by calling {@code get()} before performing the actual + * conversion. + * + * @author Christoph Strobl + * @since 1.9 + */ + @WritingConverter + public static enum NumberToNumberConverterFactory implements ConverterFactory, ConditionalConverter { + + INSTANCE; + + @Override + public Converter getConverter(Class targetType) { + return new NumberToNumber(targetType); + } + + @Override + public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { + return !sourceType.equals(targetType); + } + + private final static class NumberToNumber implements Converter { + + private final Class targetType; + + public NumberToNumber(Class targetType) { + this.targetType = targetType; + } + + @Override + public T convert(Number source) { + + if (source instanceof AtomicInteger) { + return NumberUtils.convertNumberToTargetClass(((AtomicInteger) source).get(), this.targetType); + } + if (source instanceof AtomicLong) { + return NumberUtils.convertNumberToTargetClass(((AtomicLong) source).get(), this.targetType); + } + + return NumberUtils.convertNumberToTargetClass(source, this.targetType); + } + } + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/NumberToNumberConverterFactoryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/NumberToNumberConverterFactoryUnitTests.java new file mode 100644 index 0000000000..6957764bdd --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/NumberToNumberConverterFactoryUnitTests.java @@ -0,0 +1,62 @@ +/* + * 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.convert; + +import static org.hamcrest.core.Is.*; +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.springframework.data.mongodb.core.convert.MongoConverters.NumberToNumberConverterFactory; + +/** + * @author Christoph Strobl + */ +@RunWith(Parameterized.class) +public class NumberToNumberConverterFactoryUnitTests { + + public @Parameter(0) Number source; + + public @Parameter(1) Number expected; + + @Parameters + public static Collection parameters() { + + Number[] longToInt = new Number[] { new Long(10), new Integer(10) }; + Number[] atomicIntToInt = new Number[] { new AtomicInteger(10), new Integer(10) }; + Number[] atomicIntToDouble = new Number[] { new AtomicInteger(10), new Double(10) }; + Number[] atomicLongToInt = new Number[] { new AtomicLong(10), new Integer(10) }; + Number[] atomicLongToLong = new Number[] { new AtomicLong(10), new Long(10) }; + + return Arrays. asList(longToInt, atomicIntToInt, atomicIntToDouble, atomicLongToInt, atomicLongToLong); + } + + /** + * @see DATAMONGO-1288 + */ + @Test + public void convertsToTargetTypeCorrectly() { + assertThat(NumberToNumberConverterFactory.INSTANCE.getConverter(expected.getClass()).convert(source), is(expected)); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java index 6099d0b2a8..feca9d76b9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java @@ -27,9 +27,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.hamcrest.Matcher; import org.hamcrest.collection.IsIterableContainingInOrder; +import org.hamcrest.core.Is; import org.hamcrest.core.IsEqual; import org.junit.Before; import org.junit.Test; @@ -794,7 +796,7 @@ public void mapsUpdateWithBothReadingAndWritingConverterRegistered() { } /** - * see DATAMONGO-1251 + * @see DATAMONGO-1251 */ @Test public void mapsNullValueCorrectlyForSimpleTypes() { @@ -810,7 +812,7 @@ public void mapsNullValueCorrectlyForSimpleTypes() { } /** - * see DATAMONGO-1251 + * @see DATAMONGO-1251 */ @Test public void mapsNullValueCorrectlyForJava8Date() { @@ -826,7 +828,7 @@ public void mapsNullValueCorrectlyForJava8Date() { } /** - * see DATAMONGO-1251 + * @see DATAMONGO-1251 */ @Test public void mapsNullValueCorrectlyForCollectionTypes() { @@ -842,7 +844,7 @@ public void mapsNullValueCorrectlyForCollectionTypes() { } /** - * see DATAMONGO-1251 + * @see DATAMONGO-1251 */ @Test public void mapsNullValueCorrectlyForPropertyOfNestedDocument() { @@ -857,6 +859,34 @@ public void mapsNullValueCorrectlyForPropertyOfNestedDocument() { assertThat($set.get("concreteValue.name"), nullValue()); } + /** + * @see DATAMONGO-1288 + */ + @Test + public void mapsAtomicIntegerToIntegerCorrectly() { + + Update update = new Update().set("intValue", new AtomicInteger(10)); + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(SimpleValueHolder.class)); + + DBObject $set = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$set"); + assertThat($set.get("intValue"), Is. is(10)); + } + + /** + * @see DATAMONGO-1288 + */ + @Test + public void mapsAtomicIntegerToPrimitiveIntegerCorrectly() { + + Update update = new Update().set("primIntValue", new AtomicInteger(10)); + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(SimpleValueHolder.class)); + + DBObject $set = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$set"); + assertThat($set.get("primIntValue"), Is. is(10)); + } + static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes { ListModelWrapper concreteTypeWithListAttributeOfInterfaceType; } @@ -1131,4 +1161,10 @@ static class ClassWithJava8Date { LocalDate date; } + + static class SimpleValueHolder { + + Integer intValue; + int primIntValue; + } }