Skip to content

Add a test that verifies that the default for spring.data.mongodb.uuid-representation is aligned with Spring Data's default #33532

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

Closed
gavvvr opened this issue Dec 15, 2022 · 3 comments
Assignees
Labels
type: task A general task
Milestone

Comments

@gavvvr
Copy link
Contributor

gavvvr commented Dec 15, 2022

Hi. Sorry for the question, I've posted this on StackOverflow first, but it was closed by SO community (and it will be probably further deleted too, so I will just copy my question here, which is also a proposal for change of Spring Boot defaults)


I'am talking about the spring.data.mongodb.uuid-representation property in Spring Boot, which default is still a java-legacy.
The Data Mongo team is going to change this legacy default on their side soon.

The problem is that when you start a new project based on Spring Boot and then your project gets to the point where you already have some environment with the data which you need to maintain, you can suddenly realize that the UUIDs were serialized in a legacy format, which are hard to work with in Mongo Shell and MongoDB Compass.

And nobody has warned you about that legacy format. Neither Spring Boot, nor Spring Data MongoDB docs mention anything about the approach which will be used for UUID serialization (besides the single mention in a list of Spring Boot properties).

You can also realize that if you want to query something manually for debugging purposes, you can't simply write a query by uuid, because in the simplest case of 00000000-0000-0000-0000-000000000001 the value in a document inside of Mongo will be: BinData(3, 'AAAAAAAAAAABAAAAAAAAAA==') and you have to use a sequence of tricks to manually write a primitive query by some uuid field.

You are surprised with such a default behavior of Spring Boot and try to find the motivation for this default setting, but I personally failed to do so.
What I found is that:

\x03 UUID (Old) - This used to be the UUID subtype, but was deprecated in favor of \x04. Drivers and tools for languages with a native UUID type should handle \x03 appropriately.

Make sure your applications don’t suffer from unnecessary portability issues when working with the UUID data type and avoid the legacy Binary 0x03 subtype whenever possible. If you can’t migrate your existing deployment to the new Binary 0x04 subtype, remember to configure your MongoDB tools to the correct encoding for the legacy Binary 0x03 subtype

Note to the last sentence in the quote: the official tool MongoDB Compass can't be configured to easily query for legacy UUIDs

  • support for STANDARD uuid representation (0x04) exists in Mongo Java driver for a very long time (also since 2014)
  • in 2019 developers of Mongo driver also forced its client's code to choose the representation if they want to serialize UUID:

This forces applications that encode or decode documents from MongoDB that
contain java.util.UUID values to explicitly specify the UUID representation
that they want to use. Typically, a new application would choose the
STANDARD (BSON binary subtype 4) representation, while an existing application
upgrading to the 4.0 driver would choose JAVA_LEGACY

Of course all of that makes you want to switch to the right representation (Standard v4 binary type for UUID), but Java driver won't support both worlds at the same time, so you will need to migrate the data which your system had already saved to a right format of v4 Binary for UUID. It turns out that the migration is not "a couple of lines" in mongosh, because the Mongo shell env does not provide you any tools for that, while the migration task itself is not easy because byte's order in Binary type 3 and Binary type 4 is different.

And there is a Java-based solution snippet from Studio 3T involving manual byte shifting. Since there is a chance for mistake writing the code like this manually, I've also spent quite some time to produce the solution which moves the hard work of bytes shifting to the shoulders of some library (ideally the driver's source code itself). I will leave the Java-solution relying on using MongoDB's org.mongodb:bson, because I am sure it will save someone's else time in the future and not once (full gist is here):

static void migrateUuidRepresentationFromLegacyToStandard(Document document, String key) {
    Binary legacyBinary = (Binary) document.get(key);
    UUID uuid = new BsonBinary(legacyBinary.getType(), legacyBinary.getData()).asUuid(JAVA_LEGACY);
    document.put(key, new BsonBinary(UUID_STANDARD, UuidHelper.encodeUuidToBinary(uuid, STANDARD)));
}

So, based on all of the above, I do not understand why java-legacy is a default choice for spring.data.mongodb.uuid-representation. Recently Spring Boot 3.0 was released and this behavior of mongo starter did not change. This is not something what I would expect (even for compatibility purposes) from a modern framework which which did a lot of breaking changes recently and even requires me to use Java 17 (I totally like and support the Java 17 decision btw).

I tried to understand the motivation behind that java-legacy default value for property spring.data.mongodb.uuid-representation, but failed. To me it looks like the property was added to Spring Boot just because since version 4 the Mongo driver forced its clients to make a choice and Spring Boot just probably made a wrong default choice not thinking about the default value much (just mimicking the pre-4.0 driver's behavior. Which could be a justified decision for a driver to keep legacy format by default for such a long time for compatibility reasons, but even the driver has removed this default already).

So, if there are no serious reasons to stick with legacy, please consider changing the default value of the property from java-legacy to standard. It would be a nice change for 3.0.0 release of Spring Boot, but the release has already happened.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Dec 15, 2022
@scottfrederick
Copy link
Contributor

Whenever possible, Spring Boot aligns its defaults with the defaults of the library that is being auto-configured (in this case, Spring Data MongoDB). This reduces the chance of surprise when users move between auto-configuring and manually configuring the library. If Spring Data MongoDB changes the default, then Spring Boot can react accordingly.

It might be possible for Spring Boot to not have a default at all, but to only apply the spring.data.mongodb.uuid-representation value if it is provided explicitly, This wouldn't help with your problem currently, but it would be the full decision on the default value in Spring Data MongoDB. I'll mark this issue for team attention so others can comment on whether they think we should do this.

cc @christophstrobl in case he has thoughts also.

@scottfrederick scottfrederick added the for: team-attention An issue we'd like other members of the team to review label Dec 15, 2022
@wilkinsona
Copy link
Member

If we removed our default, we'd still want to provide additional metadata so that users know what the default from Spring Data will be. As such, I don't think there's that much benefit in removing it. My preference is to leave things as they are until the change lands in Spring Data.

@philwebb philwebb removed the for: team-attention An issue we'd like other members of the team to review label Jan 18, 2023
@scottfrederick
Copy link
Contributor

We'd like to add a test to verify that the default value for spring.data.mongodb.uuid-representation matches the default in Spring Data MongoDB. That way when we upgrade to a later version of Spring Data MongoDB that includes the change to the default, we'll have a failing test that triggers Boot to change its default.

@scottfrederick scottfrederick added type: task A general task and removed status: waiting-for-triage An issue we've not yet triaged labels Jan 18, 2023
@scottfrederick scottfrederick added this to the 3.x milestone Jan 18, 2023
@philwebb philwebb modified the milestones: 3.x, 2.7.x Jan 18, 2023
@wilkinsona wilkinsona changed the title Changing the way of storing UUID in MongoDB from legacy to standard in Spring Boot default configuration Add a test that verifies that the default for spring.data.mongodb.uuid-representation is aligned with Spring Data's default Jan 19, 2023
@philwebb philwebb modified the milestones: 2.7.x, 3.1.x Nov 8, 2023
@scottfrederick scottfrederick modified the milestones: 3.1.x, 3.1.12 Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: task A general task
Projects
None yet
Development

No branches or pull requests

5 participants