From 78137c882d9c8f6465ba3283bf0dfa9c4fd7547f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 15 Mar 2021 14:01:37 +0100 Subject: [PATCH] Polishing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move hasValue(…) from DocumentAccessor to BsonUtils. Fix typo in tests. See: #3590 Original pull request: #3591. --- .../core/convert/DocumentAccessor.java | 91 +------------------ .../data/mongodb/util/BsonUtils.java | 72 ++++++++++++++- .../mongodb/core/MongoTemplateUnitTests.java | 4 +- 3 files changed, 75 insertions(+), 92 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java index ee29fea50..9c94487a3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java @@ -21,13 +21,13 @@ import java.util.Map; import org.bson.Document; import org.bson.conversions.Bson; + import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.util.BsonUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import com.mongodb.BasicDBObject; import com.mongodb.DBObject; /** @@ -123,28 +123,7 @@ class DocumentAccessor { */ @Nullable public Object get(MongoPersistentProperty property) { - - String fieldName = property.getFieldName(); - Map map = BsonUtils.asMap(document); - - if (!fieldName.contains(".")) { - return map.get(fieldName); - } - - Iterator parts = Arrays.asList(fieldName.split("\\.")).iterator(); - Map source = map; - Object result = null; - - while (source != null && parts.hasNext()) { - - result = source.get(parts.next()); - - if (parts.hasNext()) { - source = getAsMap(result); - } - } - - return result; + return BsonUtils.resolveValue(document, property.getFieldName()); } /** @@ -171,71 +150,7 @@ class DocumentAccessor { Assert.notNull(property, "Property must not be null!"); - String fieldName = property.getFieldName(); - - - if (this.document instanceof Document) { - - if (((Document) this.document).containsKey(fieldName)) { - return true; - } - } else if (this.document instanceof DBObject) { - if (((DBObject) this.document).containsField(fieldName)) { - return true; - } - } - - if (!fieldName.contains(".")) { - return false; - } - - String[] parts = fieldName.split("\\."); - Map source; - - if (this.document instanceof Document) { - source = ((Document) this.document); - } else { - source = ((DBObject) this.document).toMap(); - } - - Object result = null; - - for (int i = 1; i < parts.length; i++) { - - result = source.get(parts[i - 1]); - source = getAsMap(result); - - if (source == null) { - return false; - } - } - - return source.containsKey(parts[parts.length - 1]); - } - - /** - * Returns the given source object as map, i.e. {@link Document}s and maps as is or {@literal null} otherwise. - * - * @param source can be {@literal null}. - * @return can be {@literal null}. - */ - @Nullable - @SuppressWarnings("unchecked") - private static Map getAsMap(Object source) { - - if (source instanceof Document) { - return (Document) source; - } - - if (source instanceof BasicDBObject) { - return (BasicDBObject) source; - } - - if (source instanceof Map) { - return (Map) source; - } - - return null; + return BsonUtils.hasValue(document, property.getFieldName()); } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java index 9be81f2bd..f4bd9436e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java @@ -390,10 +390,11 @@ public class BsonUtils { * returned. If not and the key contains a path using the dot ({@code .}) notation it will try to resolve the path by * inspecting the individual parts. If one of the intermediate ones is {@literal null} or cannot be inspected further * (wrong) type, {@literal null} is returned. - * + * * @param bson the source to inspect. Must not be {@literal null}. * @param key the key to lookup. Must not be {@literal null}. * @return can be {@literal null}. + * @since 3.0.8 */ @Nullable public static Object resolveValue(Bson bson, String key) { @@ -410,7 +411,7 @@ public class BsonUtils { Object result = source.get(parts[i - 1]); - if (result == null || !(result instanceof Bson)) { + if (!(result instanceof Bson)) { return null; } @@ -420,6 +421,73 @@ public class BsonUtils { return source.get(parts[parts.length - 1]); } + /** + * Returns whether the underlying {@link Bson bson} has a value ({@literal null} or non-{@literal null}) for the given + * {@code key}. + * + * @param bson the source to inspect. Must not be {@literal null}. + * @param key the key to lookup. Must not be {@literal null}. + * @return {@literal true} if no non {@literal null} value present. + * @since 3.0.8 + */ + public static boolean hasValue(Bson bson, String key) { + + Map source = asMap(bson); + + if (source.get(key) != null) { + return true; + } + + if (!key.contains(".")) { + return false; + } + + String[] parts = key.split("\\."); + + Object result; + + for (int i = 1; i < parts.length; i++) { + + result = source.get(parts[i - 1]); + source = getAsMap(result); + + if (source == null) { + return false; + } + } + + return source.containsKey(parts[parts.length - 1]); + } + + /** + * Returns the given source object as map, i.e. {@link Document}s and maps as is or {@literal null} otherwise. + * + * @param source can be {@literal null}. + * @return can be {@literal null}. + */ + @Nullable + @SuppressWarnings("unchecked") + private static Map getAsMap(Object source) { + + if (source instanceof Document) { + return (Document) source; + } + + if (source instanceof BasicDBObject) { + return (BasicDBObject) source; + } + + if (source instanceof DBObject) { + return ((DBObject) source).toMap(); + } + + if (source instanceof Map) { + return (Map) source; + } + + return null; + } + /** * Returns given object as {@link Collection}. Will return the {@link Collection} as is if the source is a * {@link Collection} already, will convert an array into a {@link Collection} or simply create a single element diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java index abf290310..150ba5a86 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java @@ -1958,7 +1958,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { @Test // GH-3590 void shouldIncludeValueFromNestedShardKeyPath() { - WithShardKeyPoitingToNested source = new WithShardKeyPoitingToNested(); + WithShardKeyPointingToNested source = new WithShardKeyPointingToNested(); source.id = "id-1"; source.value = "v1"; source.nested = new WithNamedFields(); @@ -2333,7 +2333,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { } @Sharded(shardKey = {"value", "nested.customName"}) - static class WithShardKeyPoitingToNested { + static class WithShardKeyPointingToNested { String id; String value; WithNamedFields nested;