|
49 | 49 | import org.springframework.core.convert.support.DefaultConversionService; |
50 | 50 | import org.springframework.data.annotation.Reference; |
51 | 51 | import org.springframework.data.convert.CustomConversions; |
| 52 | +import org.springframework.data.convert.PropertyValueConverter; |
52 | 53 | import org.springframework.data.convert.TypeMapper; |
| 54 | +import org.springframework.data.convert.ValueConversionContext; |
53 | 55 | import org.springframework.data.mapping.Association; |
54 | 56 | import org.springframework.data.mapping.InstanceCreatorMetadata; |
55 | 57 | import org.springframework.data.mapping.MappingException; |
@@ -164,12 +166,11 @@ public MappingMongoConverter(DbRefResolver dbRefResolver, |
164 | 166 | this.idMapper = new QueryMapper(this); |
165 | 167 |
|
166 | 168 | this.spELContext = new SpELContext(DocumentPropertyAccessor.INSTANCE); |
167 | | - this.dbRefProxyHandler = new DefaultDbRefProxyHandler(spELContext, mappingContext, |
168 | | - (prop, bson, evaluator, path) -> { |
| 169 | + this.dbRefProxyHandler = new DefaultDbRefProxyHandler(spELContext, mappingContext, (prop, bson, evaluator, path) -> { |
169 | 170 |
|
170 | | - ConversionContext context = getConversionContext(path); |
171 | | - return MappingMongoConverter.this.getValueInternal(context, prop, bson, evaluator); |
172 | | - }); |
| 171 | + ConversionContext context = getConversionContext(path); |
| 172 | + return MappingMongoConverter.this.getValueInternal(context, prop, bson, evaluator); |
| 173 | + }); |
173 | 174 |
|
174 | 175 | this.referenceLookupDelegate = new ReferenceLookupDelegate(mappingContext, spELContext); |
175 | 176 | this.documentPointerFactory = new DocumentPointerFactory(conversionService, mappingContext); |
@@ -880,7 +881,10 @@ private void writeProperties(Bson bson, MongoPersistentEntity<?> entity, Persist |
880 | 881 | Object value = accessor.getProperty(prop); |
881 | 882 |
|
882 | 883 | if (value == null) { |
883 | | - if (prop.writeNullValues()) { |
| 884 | + |
| 885 | + if (conversions.hasValueConverter(prop)) { |
| 886 | + dbObjectAccessor.put(prop, applyPropertyConversion(null, prop, accessor)); |
| 887 | + } else { |
884 | 888 | dbObjectAccessor.put(prop, null); |
885 | 889 | } |
886 | 890 | } else if (!conversions.isSimpleType(value.getClass())) { |
@@ -918,14 +922,7 @@ protected void writePropertyInternal(@Nullable Object obj, DocumentAccessor acce |
918 | 922 | TypeInformation<?> type = prop.getTypeInformation(); |
919 | 923 |
|
920 | 924 | if (conversions.hasValueConverter(prop)) { |
921 | | - accessor.put(prop, conversions.getPropertyValueConversions().getValueConverter(prop).write(obj, |
922 | | - new MongoConversionContext(new PropertyValueProvider<>() { |
923 | | - @Nullable |
924 | | - @Override |
925 | | - public <T> T getPropertyValue(MongoPersistentProperty property) { |
926 | | - return (T) persistentPropertyAccessor.getProperty(property); |
927 | | - } |
928 | | - }, prop, this, spELContext))); |
| 925 | + accessor.put(prop, applyPropertyConversion(obj, prop, persistentPropertyAccessor)); |
929 | 926 | return; |
930 | 927 | } |
931 | 928 |
|
@@ -964,8 +961,8 @@ public <T> T getPropertyValue(MongoPersistentProperty property) { |
964 | 961 | dbRefObj = proxy.toDBRef(); |
965 | 962 | } |
966 | 963 |
|
967 | | - if(obj !=null && conversions.hasCustomWriteTarget(obj.getClass())) { |
968 | | - accessor.withCheckFieldMapping(true).put(prop, doConvert(obj, conversions.getCustomWriteTarget(obj.getClass()).get())); |
| 964 | + if (obj != null && conversions.hasCustomWriteTarget(obj.getClass())) { |
| 965 | + accessor.put(prop, doConvert(obj, conversions.getCustomWriteTarget(obj.getClass()).get())); |
969 | 966 | return; |
970 | 967 | } |
971 | 968 |
|
@@ -1267,24 +1264,34 @@ private void writeSimpleInternal(@Nullable Object value, Bson bson, String key) |
1267 | 1264 | private void writeSimpleInternal(@Nullable Object value, Bson bson, MongoPersistentProperty property, |
1268 | 1265 | PersistentPropertyAccessor<?> persistentPropertyAccessor) { |
1269 | 1266 |
|
1270 | | - DocumentAccessor accessor = new DocumentAccessor(bson).withCheckFieldMapping(true); |
| 1267 | + DocumentAccessor accessor = new DocumentAccessor(bson); |
1271 | 1268 |
|
1272 | 1269 | if (conversions.hasValueConverter(property)) { |
1273 | | - accessor.put(property, conversions.getPropertyValueConversions().getValueConverter(property).write(value, |
1274 | | - new MongoConversionContext(new PropertyValueProvider<>() { |
1275 | | - @Nullable |
1276 | | - @Override |
1277 | | - public <T> T getPropertyValue(MongoPersistentProperty property) { |
1278 | | - return (T) persistentPropertyAccessor.getProperty(property); |
1279 | | - } |
1280 | | - }, property, this, spELContext))); |
| 1270 | + accessor.put(property, applyPropertyConversion(value, property, persistentPropertyAccessor)); |
1281 | 1271 | return; |
1282 | 1272 | } |
1283 | 1273 |
|
1284 | 1274 | accessor.put(property, getPotentiallyConvertedSimpleWrite(value, |
1285 | 1275 | property.hasExplicitWriteTarget() ? property.getFieldType() : Object.class)); |
1286 | 1276 | } |
1287 | 1277 |
|
| 1278 | + @Nullable |
| 1279 | + @SuppressWarnings("unchecked") |
| 1280 | + private Object applyPropertyConversion(@Nullable Object value, MongoPersistentProperty property, |
| 1281 | + PersistentPropertyAccessor<?> persistentPropertyAccessor) { |
| 1282 | + MongoConversionContext context = new MongoConversionContext(new PropertyValueProvider<>() { |
| 1283 | + |
| 1284 | + @Nullable |
| 1285 | + @Override |
| 1286 | + public <T> T getPropertyValue(MongoPersistentProperty property) { |
| 1287 | + return (T) persistentPropertyAccessor.getProperty(property); |
| 1288 | + } |
| 1289 | + }, property, this, spELContext); |
| 1290 | + PropertyValueConverter<Object, Object, ValueConversionContext<MongoPersistentProperty>> valueConverter = conversions |
| 1291 | + .getPropertyValueConversions().getValueConverter(property); |
| 1292 | + return value != null ? valueConverter.write(value, context) : valueConverter.writeNull(context); |
| 1293 | + } |
| 1294 | + |
1288 | 1295 | /** |
1289 | 1296 | * Checks whether we have a custom conversion registered for the given value into an arbitrary simple Mongo type. |
1290 | 1297 | * Returns the converted value if so. If not, we perform special enum handling or simply return the value as is. |
@@ -1925,14 +1932,18 @@ public <T> T getPropertyValue(MongoPersistentProperty property) { |
1925 | 1932 | String expression = property.getSpelExpression(); |
1926 | 1933 | Object value = expression != null ? evaluator.evaluate(expression) : accessor.get(property); |
1927 | 1934 |
|
1928 | | - if (value == null) { |
1929 | | - return null; |
1930 | | - } |
1931 | | - |
1932 | 1935 | CustomConversions conversions = context.getCustomConversions(); |
1933 | 1936 | if (conversions.hasValueConverter(property)) { |
1934 | | - return (T) conversions.getPropertyValueConversions().getValueConverter(property).read(value, |
1935 | | - new MongoConversionContext(this, property, context.getSourceConverter(), spELContext)); |
| 1937 | + MongoConversionContext conversionContext = new MongoConversionContext(this, property, |
| 1938 | + context.getSourceConverter(), spELContext); |
| 1939 | + PropertyValueConverter<Object, Object, ValueConversionContext<MongoPersistentProperty>> valueConverter = conversions |
| 1940 | + .getPropertyValueConversions().getValueConverter(property); |
| 1941 | + return (T) (value != null ? valueConverter.read(value, conversionContext) |
| 1942 | + : valueConverter.readNull(conversionContext)); |
| 1943 | + } |
| 1944 | + |
| 1945 | + if (value == null) { |
| 1946 | + return null; |
1936 | 1947 | } |
1937 | 1948 |
|
1938 | 1949 | ConversionContext contextToUse = context.forProperty(property); |
|
0 commit comments