Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property path with whitespace inconsistently throws exception #3121

Open
boly38 opened this issue Jul 3, 2024 · 2 comments
Open

Property path with whitespace inconsistently throws exception #3121

boly38 opened this issue Jul 3, 2024 · 2 comments
Assignees
Labels
type: bug A general bug

Comments

@boly38
Copy link

boly38 commented Jul 3, 2024

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 ooo is detected under properties
  • for the B use case, ("properties. P") two word P and are detected under properties, and as is 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 : class and _class,
  • . is not autorized
  • $ is not autorized as first character
    I appreciate some reference to complete this, if any

regards.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 3, 2024
@christophstrobl
Copy link
Member

Thank you @boly38 for getting in touch. Spring Data MongoDB is mainly operating upon the java domain model and does not necessarily have the same behaviour as when using the Mongo Shell. That being said, PropertyPath is used as an abstraction to navigate within the domain model. Therefore it is not tied to any MongoDB specifics.
The different behaviour is due to how the path is split into parts using camel case detection.

From what I understand is that you are storing data in MongoDB, using keys that contain leading whitespaces like the following right?

{
  "_id": "...",
  "name": "docA",
  "properties": {
    " Major": "blob"
  }
}

I think we'll have to deal with this issue both here (path resolution) and in data-mongo (handling of fields containing whitespaces).

@christophstrobl christophstrobl added the for: team-attention An issue we need to discuss as a team to make progress label Jul 4, 2024
@mp911de mp911de changed the title PropertyPath : IllegalArgumentException: Name must not be null or empty Property path with whitespace inconsistently throws exception Jul 22, 2024
@mp911de mp911de added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged for: team-attention An issue we need to discuss as a team to make progress labels Jul 22, 2024
@mp911de
Copy link
Member

mp911de commented Jul 22, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants