|
81 | 81 | import org.springframework.data.mongodb.core.mapping.Unwrapped;
|
82 | 82 | import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
|
83 | 83 | import org.springframework.data.util.ClassTypeInformation;
|
| 84 | +import org.springframework.lang.NonNull; |
| 85 | +import org.springframework.lang.Nullable; |
84 | 86 | import org.springframework.test.util.ReflectionTestUtils;
|
85 | 87 |
|
86 | 88 | import com.mongodb.BasicDBList;
|
@@ -2428,6 +2430,98 @@ void shouldUseMostConcreteCustomConversionTargetOnRead() {
|
2428 | 2430 | verify(subTypeOfGenericTypeConverter).convert(eq(source));
|
2429 | 2431 | }
|
2430 | 2432 |
|
| 2433 | + |
| 2434 | + @Test // GH-3660 |
| 2435 | + void usesCustomConverterForMapTypesOnWrite() { |
| 2436 | + |
| 2437 | + |
| 2438 | + converter = new MappingMongoConverter(resolver, mappingContext); |
| 2439 | + converter.setCustomConversions(MongoCustomConversions.create(it -> { |
| 2440 | + it.registerConverter(new TypeImplementingMapToDocumentConverter()); |
| 2441 | + })); |
| 2442 | + converter.afterPropertiesSet(); |
| 2443 | + |
| 2444 | + TypeImplementingMap source = new TypeImplementingMap("one", 2); |
| 2445 | + org.bson.Document target = new org.bson.Document(); |
| 2446 | + |
| 2447 | + converter.write(source, target); |
| 2448 | + |
| 2449 | + assertThat(target).containsEntry("1st", "one").containsEntry("2nd", 2); |
| 2450 | + } |
| 2451 | + |
| 2452 | + @Test // GH-3660 |
| 2453 | + void usesCustomConverterForTypesImplementingMapOnWrite() { |
| 2454 | + |
| 2455 | + converter = new MappingMongoConverter(resolver, mappingContext); |
| 2456 | + converter.setCustomConversions(MongoCustomConversions.create(it -> { |
| 2457 | + it.registerConverter(new TypeImplementingMapToDocumentConverter()); |
| 2458 | + })); |
| 2459 | + converter.afterPropertiesSet(); |
| 2460 | + |
| 2461 | + TypeImplementingMap source = new TypeImplementingMap("one", 2); |
| 2462 | + org.bson.Document target = new org.bson.Document(); |
| 2463 | + |
| 2464 | + converter.write(source, target); |
| 2465 | + |
| 2466 | + assertThat(target).containsEntry("1st", "one").containsEntry("2nd", 2); |
| 2467 | + } |
| 2468 | + |
| 2469 | + @Test // GH-3660 |
| 2470 | + void usesCustomConverterForTypesImplementingMapOnRead() { |
| 2471 | + |
| 2472 | + converter = new MappingMongoConverter(resolver, mappingContext); |
| 2473 | + converter.setCustomConversions(MongoCustomConversions.create(it -> { |
| 2474 | + it.registerConverter(new DocumentToTypeImplementingMapConverter()); |
| 2475 | + })); |
| 2476 | + converter.afterPropertiesSet(); |
| 2477 | + |
| 2478 | + org.bson.Document source = new org.bson.Document("1st", "one") |
| 2479 | + .append("2nd", 2) |
| 2480 | + .append("_class", TypeImplementingMap.class.getName()); |
| 2481 | + |
| 2482 | + TypeImplementingMap target = converter.read(TypeImplementingMap.class, source); |
| 2483 | + |
| 2484 | + assertThat(target).isEqualTo(new TypeImplementingMap("one", 2)); |
| 2485 | + } |
| 2486 | + |
| 2487 | + @Test // GH-3660 |
| 2488 | + void usesCustomConverterForPropertiesUsingTypesThatImplementMapOnWrite() { |
| 2489 | + |
| 2490 | + converter = new MappingMongoConverter(resolver, mappingContext); |
| 2491 | + converter.setCustomConversions(MongoCustomConversions.create(it -> { |
| 2492 | + it.registerConverter(new TypeImplementingMapToDocumentConverter()); |
| 2493 | + })); |
| 2494 | + converter.afterPropertiesSet(); |
| 2495 | + |
| 2496 | + TypeWrappingTypeImplementingMap source = new TypeWrappingTypeImplementingMap(); |
| 2497 | + source.typeImplementingMap = new TypeImplementingMap("one", 2); |
| 2498 | + org.bson.Document target = new org.bson.Document(); |
| 2499 | + |
| 2500 | + converter.write(source, target); |
| 2501 | + |
| 2502 | + assertThat(target).containsEntry("typeImplementingMap", new org.bson.Document("1st", "one").append("2nd", 2)); |
| 2503 | + } |
| 2504 | + |
| 2505 | + @Test // GH-3660 |
| 2506 | + void usesCustomConverterForPropertiesUsingTypesImplementingMapOnRead() { |
| 2507 | + |
| 2508 | + converter = new MappingMongoConverter(resolver, mappingContext); |
| 2509 | + converter.setCustomConversions(MongoCustomConversions.create(it -> { |
| 2510 | + it.registerConverter(new DocumentToTypeImplementingMapConverter()); |
| 2511 | + })); |
| 2512 | + converter.afterPropertiesSet(); |
| 2513 | + |
| 2514 | + org.bson.Document source = new org.bson.Document("typeImplementingMap", |
| 2515 | + new org.bson.Document("1st", "one") |
| 2516 | + .append("2nd", 2)) |
| 2517 | + .append("_class", TypeWrappingTypeImplementingMap.class.getName()); |
| 2518 | + |
| 2519 | + TypeWrappingTypeImplementingMap target = converter.read(TypeWrappingTypeImplementingMap.class, source); |
| 2520 | + |
| 2521 | + assertThat(target.typeImplementingMap).isEqualTo(new TypeImplementingMap("one", 2)); |
| 2522 | + } |
| 2523 | + |
| 2524 | + |
2431 | 2525 | static class GenericType<T> {
|
2432 | 2526 | T content;
|
2433 | 2527 | }
|
@@ -2971,4 +3065,106 @@ public SubTypeOfGenericType convert(org.bson.Document source) {
|
2971 | 3065 | return target;
|
2972 | 3066 | }
|
2973 | 3067 | }
|
| 3068 | + |
| 3069 | + @WritingConverter |
| 3070 | + static class TypeImplementingMapToDocumentConverter implements Converter<TypeImplementingMap, org.bson.Document> { |
| 3071 | + |
| 3072 | + @Nullable |
| 3073 | + @Override |
| 3074 | + public org.bson.Document convert(TypeImplementingMap source) { |
| 3075 | + return new org.bson.Document("1st", source.val1).append("2nd", source.val2); |
| 3076 | + } |
| 3077 | + } |
| 3078 | + |
| 3079 | + @ReadingConverter |
| 3080 | + static class DocumentToTypeImplementingMapConverter implements Converter<org.bson.Document, TypeImplementingMap> { |
| 3081 | + |
| 3082 | + @Nullable |
| 3083 | + @Override |
| 3084 | + public TypeImplementingMap convert(org.bson.Document source) { |
| 3085 | + return new TypeImplementingMap(source.getString("1st"), source.getInteger("2nd")); |
| 3086 | + } |
| 3087 | + } |
| 3088 | + |
| 3089 | + static class TypeWrappingTypeImplementingMap { |
| 3090 | + |
| 3091 | + String id; |
| 3092 | + TypeImplementingMap typeImplementingMap; |
| 3093 | + } |
| 3094 | + |
| 3095 | + @EqualsAndHashCode |
| 3096 | + static class TypeImplementingMap implements Map<String,String> { |
| 3097 | + |
| 3098 | + String val1; |
| 3099 | + int val2; |
| 3100 | + |
| 3101 | + public TypeImplementingMap(String val1, int val2) { |
| 3102 | + this.val1 = val1; |
| 3103 | + this.val2 = val2; |
| 3104 | + } |
| 3105 | + |
| 3106 | + @Override |
| 3107 | + public int size() { |
| 3108 | + return 0; |
| 3109 | + } |
| 3110 | + |
| 3111 | + @Override |
| 3112 | + public boolean isEmpty() { |
| 3113 | + return false; |
| 3114 | + } |
| 3115 | + |
| 3116 | + @Override |
| 3117 | + public boolean containsKey(Object key) { |
| 3118 | + return false; |
| 3119 | + } |
| 3120 | + |
| 3121 | + @Override |
| 3122 | + public boolean containsValue(Object value) { |
| 3123 | + return false; |
| 3124 | + } |
| 3125 | + |
| 3126 | + @Override |
| 3127 | + public String get(Object key) { |
| 3128 | + return null; |
| 3129 | + } |
| 3130 | + |
| 3131 | + @Nullable |
| 3132 | + @Override |
| 3133 | + public String put(String key, String value) { |
| 3134 | + return null; |
| 3135 | + } |
| 3136 | + |
| 3137 | + @Override |
| 3138 | + public String remove(Object key) { |
| 3139 | + return null; |
| 3140 | + } |
| 3141 | + |
| 3142 | + @Override |
| 3143 | + public void putAll(@NonNull Map<? extends String, ? extends String> m) { |
| 3144 | + |
| 3145 | + } |
| 3146 | + |
| 3147 | + @Override |
| 3148 | + public void clear() { |
| 3149 | + |
| 3150 | + } |
| 3151 | + |
| 3152 | + @NonNull |
| 3153 | + @Override |
| 3154 | + public Set<String> keySet() { |
| 3155 | + return null; |
| 3156 | + } |
| 3157 | + |
| 3158 | + @NonNull |
| 3159 | + @Override |
| 3160 | + public Collection<String> values() { |
| 3161 | + return null; |
| 3162 | + } |
| 3163 | + |
| 3164 | + @NonNull |
| 3165 | + @Override |
| 3166 | + public Set<Entry<String, String>> entrySet() { |
| 3167 | + return null; |
| 3168 | + } |
| 3169 | + } |
2974 | 3170 | }
|
0 commit comments