spring-projects / spring-projects/spring-data-commons
Property path with whitespace inconsistently throws exception
@christophstrobl is already working on this.
Since Jul 8, 2024.
- Dominant language
- Java
- Stars
- 838
- Forks
- 730
- PR merge metrics
- No merged PRs in 30d
Description
Hi here 👋 ,
What is the issue ?
On my project I want to update a given MongoDB document having properties map as subdocument.
I'm using org.springframework.data:spring-data-commons:jar:3.1.11 (and spring data mongodb 4.1.11) .
I encounter IllegalArgumentException: Name must not be null or empty from PropertyPath.java:82 while trying to patch a given document properties.
Context - How to reproduce ?
- Given a following MongoDB content :
{"_id": .., "name":"docA", "properties": {"bien" : "dd", "OK" : "eee"}}
ℹ️ A usecase - I encounter no issue to set / unset a property having " " space in the beginning of a property key value with a word starting with lowercase; example :
update.set("properties. ooo", "space minus");
or
update.unset("properties. ooo");
(...)
mongoTemplate.findAndModify(query, update, options, documentClass);
ℹ️ B usecase - BUT now if I'm doing the same thing with a word starting with an uppercase, I encounter an issue :
update.set("properties. P", "space Major");
or
update.unset("properties. P");
(...)
mongoTemplate.findAndModify(query, update, options, documentClass);
java.lang.IllegalArgumentException: Name must not be null or empty
stack extract
java.lang.IllegalArgumentException: Name must not be null or empty
at org.springframework.util.Assert.hasText(Assert.java:294)
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:82)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:443)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:476)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:419)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:403)
at org.springframework.data.mapping.PropertyPath.lambda$from$0(PropertyPath.java:375)
at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:354)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.forName(QueryMapper.java:1310)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.getPath(QueryMapper.java:1243)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.<init>(QueryMapper.java:1136)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.<init>(QueryMapper.java:1113)
at org.springframework.data.mongodb.core.convert.UpdateMapper$MetadataBackedUpdateField.<init>(UpdateMapper.java:294)
at org.springframework.data.mongodb.core.convert.UpdateMapper.createPropertyField(UpdateMapper.java:254)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:156)
at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
at org.springframework.data.mongodb.core.convert.QueryMapper.convertSimpleOrDocument(QueryMapper.java:596)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedKeyword(QueryMapper.java:403)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:150)
at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
at org.springframework.data.mongodb.core.QueryOperations$UpdateContext.getMappedUpdate(QueryOperations.java:861)
at org.springframework.data.mongodb.core.MongoTemplate.doFindAndModify(MongoTemplate.java:2698)
at org.springframework.data.mongodb.core.MongoTemplate.findAndModify(MongoTemplate.java:1088)
at org.springframework.data.mongodb.core.MongoTemplate.findAndModify(MongoTemplate.java:1063)
Further analysis
By debugging some test with different value, I can state that spring-data-commons > PropertyPath component is processing some part of the update query and will see some field following spring data internal logic :
- for the A use case, ("properties. ooo") only the word
ooois detected under properties - for the B use case, ("properties. P") two word
Pandare detected under properties, and asis empty, the assert exception (l82) throws an exception.
With mongo Shell, I'm trying to reproduce but no issue, all is fine (usecase B too)
case A OK
db.myDocs.find({"name":"docA"},{"properties":1})
db.myDocs.update({"name":"docA"},{ "$set": {"properties. minus":"blob"}})
db.myDocs.update({"name":"docA"},{ "$unset": {"properties. minus":1}})
case B OK
db.myDocs.update({"name":"docA"},{ "$set": {"properties. Major":"blob"}})
db.myDocs.find({"name":"docA"},{"properties":1})
db.myDocs.update({"name":"docA"},{ "$unset": {"properties. Major":1}})
What did I expect
I expect the update to work like on mongo shell.
I though this is a bug at the PropertyPath layer (but not sure) Or maybe in spring data mongodb?
If this is stated as "not a bug",
I would like to know the recommendation for this kind of update for the "key" value.
Example (mongo manual):
- exclude this words :
classand_class, .is not autorized$is not autorized as first character
I appreciate some reference to complete this, if any
regards.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.