|
27 | 27 | import java.time.LocalDateTime;
|
28 | 28 | import java.time.temporal.ChronoUnit;
|
29 | 29 | import java.util.*;
|
| 30 | +import java.util.function.Consumer; |
30 | 31 | import java.util.function.Function;
|
31 | 32 | import java.util.stream.Stream;
|
32 | 33 |
|
@@ -677,15 +678,144 @@ void readsListOfMapsCorrectly() {
|
677 | 678 | assertThat(wrapper.listOfMaps.get(0).get("Foo")).isEqualTo(Locale.ENGLISH);
|
678 | 679 | }
|
679 | 680 |
|
680 |
| - @ParameterizedTest // GH-4571 |
| 681 | + @ParameterizedTest(name = "{4}") // GH-4571 |
681 | 682 | @MethodSource("listMapSetReadingSource")
|
682 | 683 | <T> void initializesListMapSetPropertiesIfRequiredOnRead(org.bson.Document source, Class<T> type,
|
683 |
| - Function<T, Object> valueFunction, Object expectedValue) { |
| 684 | + Function<T, Object> valueFunction, Object expectedValue, String displayName) { |
684 | 685 |
|
685 | 686 | T target = converter.read(type, source);
|
686 | 687 | assertThat(target).extracting(valueFunction).isEqualTo(expectedValue);
|
687 | 688 | }
|
688 | 689 |
|
| 690 | + private static Stream<Arguments> listMapSetReadingSource() { |
| 691 | + |
| 692 | + Stream<Arguments> initialList = fixtureFor("contacts", CollectionWrapper.class, CollectionWrapper::getContacts, |
| 693 | + builder -> { |
| 694 | + |
| 695 | + builder.onValue(Collections.emptyList()).expect(Collections.emptyList()); |
| 696 | + builder.onNull().expect(null); |
| 697 | + builder.onEmpty().expect(null); |
| 698 | + }); |
| 699 | + |
| 700 | + Stream<Arguments> initializedList = fixtureFor("autoInitList", CollectionWrapper.class, |
| 701 | + CollectionWrapper::getAutoInitList, builder -> { |
| 702 | + |
| 703 | + builder.onValue(Collections.emptyList()).expect(Collections.emptyList()); |
| 704 | + builder.onNull().expect(null); |
| 705 | + builder.onEmpty().expect(Collections.singletonList("spring")); |
| 706 | + }); |
| 707 | + |
| 708 | + Stream<Arguments> initialSet = fixtureFor("contactsSet", CollectionWrapper.class, CollectionWrapper::getContactsSet, |
| 709 | + builder -> { |
| 710 | + |
| 711 | + builder.onValue(Collections.emptyList()).expect(Collections.emptySet()); |
| 712 | + builder.onNull().expect(null); |
| 713 | + builder.onEmpty().expect(null); |
| 714 | + }); |
| 715 | + |
| 716 | + Stream<Arguments> initialMap = fixtureFor("map", ClassWithMapProperty.class, ClassWithMapProperty::getMap, |
| 717 | + builder -> { |
| 718 | + |
| 719 | + builder.onValue(new org.bson.Document()).expect(Collections.emptyMap()); |
| 720 | + builder.onNull().expect(null); |
| 721 | + builder.onEmpty().expect(null); |
| 722 | + }); |
| 723 | + |
| 724 | + Stream<Arguments> initializedMap = fixtureFor("autoInitMap", ClassWithMapProperty.class, |
| 725 | + ClassWithMapProperty::getAutoInitMap, builder -> { |
| 726 | + |
| 727 | + builder.onValue(new org.bson.Document()).expect(Collections.emptyMap()); |
| 728 | + builder.onNull().expect(null); |
| 729 | + builder.onEmpty().expect(Collections.singletonMap("spring", "data")); |
| 730 | + }); |
| 731 | + |
| 732 | + return Stream.of(initialList, initializedList, initialSet, initialMap, initializedMap).flatMap(Function.identity()); |
| 733 | + } |
| 734 | + |
| 735 | + static <T> Stream<Arguments> fixtureFor(String field, Class<T> type, Function<T, Object> valueFunction, |
| 736 | + Consumer<FixtureBuilder> builderConsumer) { |
| 737 | + |
| 738 | + FixtureBuilder builder = new FixtureBuilder(field, type, valueFunction); |
| 739 | + |
| 740 | + builderConsumer.accept(builder); |
| 741 | + |
| 742 | + return builder.fixtures.stream(); |
| 743 | + } |
| 744 | + |
| 745 | + /** |
| 746 | + * Builder for fixtures. |
| 747 | + */ |
| 748 | + static class FixtureBuilder { |
| 749 | + |
| 750 | + private final String field; |
| 751 | + private final Class<?> typeUnderTest; |
| 752 | + private final Function<?, Object> valueMappingFunction; |
| 753 | + final List<Arguments> fixtures = new ArrayList<>(); |
| 754 | + |
| 755 | + FixtureBuilder(String field, Class<?> typeUnderTest, Function<?, Object> valueMappingFunction) { |
| 756 | + this.field = field; |
| 757 | + this.typeUnderTest = typeUnderTest; |
| 758 | + this.valueMappingFunction = valueMappingFunction; |
| 759 | + } |
| 760 | + |
| 761 | + /** |
| 762 | + * If the document value is {@code null}. |
| 763 | + */ |
| 764 | + FixtureStep onNull() { |
| 765 | + return new FixtureStep(false, null); |
| 766 | + } |
| 767 | + |
| 768 | + /** |
| 769 | + * If the document value is {@code value}. |
| 770 | + */ |
| 771 | + FixtureStep onValue(@Nullable Object value) { |
| 772 | + return new FixtureStep(false, value); |
| 773 | + } |
| 774 | + |
| 775 | + /** |
| 776 | + * If the document does not contain the field. |
| 777 | + */ |
| 778 | + FixtureStep onEmpty() { |
| 779 | + return new FixtureStep(true, null); |
| 780 | + } |
| 781 | + |
| 782 | + class FixtureStep { |
| 783 | + |
| 784 | + private final boolean empty; |
| 785 | + private final @Nullable Object documentValue; |
| 786 | + |
| 787 | + public FixtureStep(boolean empty, @Nullable Object documentValue) { |
| 788 | + this.empty = empty; |
| 789 | + this.documentValue = documentValue; |
| 790 | + } |
| 791 | + |
| 792 | + /** |
| 793 | + * Then expect {@code expectedValue}. |
| 794 | + * |
| 795 | + * @param expectedValue |
| 796 | + */ |
| 797 | + void expect(@Nullable Object expectedValue) { |
| 798 | + |
| 799 | + Arguments fixture; |
| 800 | + if (empty) { |
| 801 | + fixture = Arguments.of(new org.bson.Document(), typeUnderTest, valueMappingFunction, expectedValue, |
| 802 | + "Empty document expecting '%s' at type %s".formatted(expectedValue, typeUnderTest.getSimpleName())); |
| 803 | + } else { |
| 804 | + |
| 805 | + String valueDescription = (documentValue == null ? "null" |
| 806 | + : (documentValue + " (" + documentValue.getClass().getSimpleName()) + ")"); |
| 807 | + |
| 808 | + fixture = Arguments.of(new org.bson.Document(field, documentValue), typeUnderTest, valueMappingFunction, |
| 809 | + expectedValue, "Field '%s' with value %s expecting '%s' at type %s".formatted(field, valueDescription, |
| 810 | + expectedValue, typeUnderTest.getSimpleName())); |
| 811 | + } |
| 812 | + |
| 813 | + fixtures.add(fixture); |
| 814 | + } |
| 815 | + } |
| 816 | + |
| 817 | + } |
| 818 | + |
689 | 819 | @Test // DATAMONGO-259
|
690 | 820 | void writesPlainMapOfCollectionsCorrectly() {
|
691 | 821 |
|
@@ -2931,7 +3061,8 @@ void shouldNotSplitKeyNamesWithDotOnReadOfNestedIfFieldTypeIsKey() {
|
2931 | 3061 |
|
2932 | 3062 | org.bson.Document source = new org.bson.Document("nested", new org.bson.Document("field.name.with.dots", "A"));
|
2933 | 3063 |
|
2934 |
| - WrapperForTypeWithPropertyHavingDotsInFieldName target = converter.read(WrapperForTypeWithPropertyHavingDotsInFieldName.class, source); |
| 3064 | + WrapperForTypeWithPropertyHavingDotsInFieldName target = converter |
| 3065 | + .read(WrapperForTypeWithPropertyHavingDotsInFieldName.class, source); |
2935 | 3066 | assertThat(target.nested).isNotNull();
|
2936 | 3067 | assertThat(target.nested.value).isEqualTo("A");
|
2937 | 3068 | }
|
@@ -2964,14 +3095,16 @@ void readShouldAllowDotsInMapKeyNameIfConfigured() {
|
2964 | 3095 | person.firstname = "bart";
|
2965 | 3096 | person.lastname = "simpson";
|
2966 | 3097 |
|
2967 |
| - org.bson.Document source = new org.bson.Document("mapOfPersons", new org.bson.Document("map.key.with.dots", write(person))); |
| 3098 | + org.bson.Document source = new org.bson.Document("mapOfPersons", |
| 3099 | + new org.bson.Document("map.key.with.dots", write(person))); |
2968 | 3100 |
|
2969 | 3101 | ClassWithMapProperty target = converter.read(ClassWithMapProperty.class, source);
|
2970 | 3102 |
|
2971 | 3103 | assertThat(target.mapOfPersons).containsEntry("map.key.with.dots", person);
|
2972 | 3104 | }
|
2973 | 3105 |
|
2974 |
| - @ValueSource(classes = { ComplexIdAndNoAnnotation.class, ComplexIdAndIdAnnotation.class, ComplexIdAndMongoIdAnnotation.class, ComplexIdAndFieldAnnotation.class }) |
| 3106 | + @ValueSource(classes = { ComplexIdAndNoAnnotation.class, ComplexIdAndIdAnnotation.class, |
| 3107 | + ComplexIdAndMongoIdAnnotation.class, ComplexIdAndFieldAnnotation.class }) |
2975 | 3108 | @ParameterizedTest // GH-4524
|
2976 | 3109 | void projectShouldReadComplexIdType(Class<?> projectionTargetType) {
|
2977 | 3110 |
|
@@ -2999,49 +3132,6 @@ org.bson.Document write(Object source) {
|
2999 | 3132 | return target;
|
3000 | 3133 | }
|
3001 | 3134 |
|
3002 |
| - private static Stream<Arguments> listMapSetReadingSource() { |
3003 |
| - |
3004 |
| - Function<CollectionWrapper, Object> contacts = CollectionWrapper::getContacts; |
3005 |
| - Function<CollectionWrapper, Object> contactsSet = CollectionWrapper::getContactsSet; |
3006 |
| - Function<CollectionWrapper, Object> autoInitList = CollectionWrapper::getAutoInitList; |
3007 |
| - Function<ClassWithMapProperty, Object> map = ClassWithMapProperty::getMap; |
3008 |
| - Function<ClassWithMapProperty, Object> autoInitMap = ClassWithMapProperty::getAutoInitMap; |
3009 |
| - |
3010 |
| - return Stream.of( // |
3011 |
| - |
3012 |
| - // List |
3013 |
| - Arguments.of(new org.bson.Document("contacts", Collections.emptyList()), CollectionWrapper.class, contacts, |
3014 |
| - Collections.emptyList()), |
3015 |
| - Arguments.of(new org.bson.Document("contacts", null), CollectionWrapper.class, contacts, null), |
3016 |
| - Arguments.of(new org.bson.Document(), CollectionWrapper.class, contacts, null), |
3017 |
| - |
3018 |
| - // ctor initialized List |
3019 |
| - Arguments.of(new org.bson.Document("autoInitList", Collections.emptyList()), CollectionWrapper.class, |
3020 |
| - autoInitList, Collections.emptyList()), |
3021 |
| - Arguments.of(new org.bson.Document("autoInitList", null), CollectionWrapper.class, autoInitList, null), |
3022 |
| - Arguments.of(new org.bson.Document(), CollectionWrapper.class, autoInitList, |
3023 |
| - Collections.singletonList("spring")), |
3024 |
| - |
3025 |
| - // Set |
3026 |
| - Arguments.of(new org.bson.Document("contactsSet", Collections.emptyList()), CollectionWrapper.class, |
3027 |
| - contactsSet, Collections.emptySet()), |
3028 |
| - Arguments.of(new org.bson.Document("contactsSet", null), CollectionWrapper.class, contactsSet, null), |
3029 |
| - Arguments.of(new org.bson.Document(), CollectionWrapper.class, contactsSet, null), |
3030 |
| - |
3031 |
| - // Map |
3032 |
| - Arguments.of(new org.bson.Document("map", new org.bson.Document()), ClassWithMapProperty.class, map, |
3033 |
| - Collections.emptyMap()), |
3034 |
| - Arguments.of(new org.bson.Document("map", null), ClassWithMapProperty.class, map, null), |
3035 |
| - Arguments.of(new org.bson.Document(), ClassWithMapProperty.class, map, null), |
3036 |
| - |
3037 |
| - // ctor initialized Map |
3038 |
| - Arguments.of(new org.bson.Document("autoInitMap", new org.bson.Document()), ClassWithMapProperty.class, |
3039 |
| - autoInitMap, Collections.emptyMap()), |
3040 |
| - Arguments.of(new org.bson.Document("autoInitMap", null), ClassWithMapProperty.class, autoInitMap, null), |
3041 |
| - Arguments.of(new org.bson.Document(), ClassWithMapProperty.class, autoInitMap, |
3042 |
| - Collections.singletonMap("spring", "data"))); |
3043 |
| - } |
3044 |
| - |
3045 | 3135 | static class GenericType<T> {
|
3046 | 3136 | T content;
|
3047 | 3137 | }
|
@@ -3135,7 +3225,9 @@ public boolean equals(Object o) {
|
3135 | 3225 | return false;
|
3136 | 3226 | }
|
3137 | 3227 | Person person = (Person) o;
|
3138 |
| - return Objects.equals(id, person.id) && Objects.equals(birthDate, person.birthDate) && Objects.equals(firstname, person.firstname) && Objects.equals(lastname, person.lastname) && Objects.equals(addresses, person.addresses); |
| 3228 | + return Objects.equals(id, person.id) && Objects.equals(birthDate, person.birthDate) |
| 3229 | + && Objects.equals(firstname, person.firstname) && Objects.equals(lastname, person.lastname) |
| 3230 | + && Objects.equals(addresses, person.addresses); |
3139 | 3231 | }
|
3140 | 3232 |
|
3141 | 3233 | @Override
|
@@ -3922,10 +4014,12 @@ static class WithFieldWrite {
|
3922 | 4014 | @org.springframework.data.mongodb.core.mapping.Field(
|
3923 | 4015 | write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Integer writeAlways;
|
3924 | 4016 |
|
3925 |
| - @org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field( |
| 4017 | + @org.springframework.data.mongodb.core.mapping.DBRef |
| 4018 | + @org.springframework.data.mongodb.core.mapping.Field( |
3926 | 4019 | write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Person writeNonNullPerson;
|
3927 | 4020 |
|
3928 |
| - @org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field( |
| 4021 | + @org.springframework.data.mongodb.core.mapping.DBRef |
| 4022 | + @org.springframework.data.mongodb.core.mapping.Field( |
3929 | 4023 | write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPerson;
|
3930 | 4024 |
|
3931 | 4025 | }
|
@@ -4157,8 +4251,7 @@ static class WrapperForTypeWithPropertyHavingDotsInFieldName {
|
4157 | 4251 |
|
4158 | 4252 | static class WithPropertyHavingDotsInFieldName {
|
4159 | 4253 |
|
4160 |
| - @Field(name = "field.name.with.dots", nameType = Type.KEY) |
4161 |
| - String value; |
| 4254 | + @Field(name = "field.name.with.dots", nameType = Type.KEY) String value; |
4162 | 4255 | }
|
4163 | 4256 |
|
4164 | 4257 | static class ComplexIdAndFieldAnnotation {
|
|
0 commit comments