Skip to content

how to sort nulls#1418

Merged
otaviojava merged 4 commits intojakartaee:mainfrom
njr-11:1416-how-to-sort-nulls
Apr 15, 2026
Merged

how to sort nulls#1418
otaviojava merged 4 commits intojakartaee:mainfrom
njr-11:1416-how-to-sort-nulls

Conversation

@njr-11
Copy link
Copy Markdown
Member

@njr-11 njr-11 commented Apr 3, 2026

Resolves #1416 which requested a way to indicate whether null values should be sorted first or last. This is done with methods .nullsFirst() and .nullsLast() that can be invoked on a Sort instance to obtain an otherwise equivalent instance that specifies how to sort nulls. This pattern aligns with designed PageRequest in Jakarta Data. I have included language that allows NoSQL databases to reject a Sort instance that has nullsFirst or nullsLast if the NoSQL database is not capable of it.

@njr-11 njr-11 added this to the 1.1 milestone Apr 3, 2026
@njr-11 njr-11 added the enhancement New feature or request label Apr 3, 2026
public record Sort<T>(String property,
boolean isAscending,
boolean ignoreCase,
Boolean orderNullsFirst) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you want to include this in Jakarta Persistence, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you want to include this in Jakarta Persistence, right?

Yes, Jakarta Persistence has it. According to an AI search, a few NoSQL databases have it as well, although you will know more the detail on that.

Copy link
Copy Markdown
Contributor

@otaviojava otaviojava left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null ordering is fundamentally non-portable across databases.

Given that Jakarta Data aims to be domain-centric, exposing null ordering as a first-class abstraction would promote an infrastructure concern into the domain model, which seems misaligned with its goals.

A better approach would be to treat null ordering as a provider-specific capability (e.g., via hints or extensions), rather than standardizing it in the core API.

This allows the specification to remain focused on domain concepts while still providing an escape hatch for datastore-specific behavior.

@FroMage
Copy link
Copy Markdown

FroMage commented Apr 3, 2026

Do you have an example of what it would look like if this was left to specific implementations? I'm afraid this will only make user's life more complicated.

@otaviojava
Copy link
Copy Markdown
Contributor

Do you have an example of what it would look like if this was left to specific implementations? I'm afraid this will only make user's life more complicated.

The complexity already exists — the question is where we choose to expose it. I’m not suggesting we ignore this case.

I agree there’s a risk of making advanced use cases harder if we don’t support it directly, but there is a trade-off.

If we bring these concerns into the core API, we introduce a different kind of complexity: instead of making a few advanced cases harder, we make the entire API heavier for everyone.

Sorting itself already has multiple non-portable dimensions, for example:

  • schemaless vs structured models (missing vs null fields)
  • collation and locale-specific ordering
  • sorting on nested or joined data
  • sorting on computed values
  • index-driven sorting constraints in some datastores

If we try to standardize all of these in the core API, it quickly becomes harder to understand and reason about than the problem it is trying to solve.

IMHO: A better balance is to keep the core API focused on universally meaningful concepts (such as basic ordering), and allow provider-specific extensions or hints for cases like null handling.

@njr-11
Copy link
Copy Markdown
Member Author

njr-11 commented Apr 3, 2026

we make the entire API heavier for everyone

I don't see how what we proposed here makes the API heavier. If you have data without nulls or a database that isn't capable of sorting them, you use the Sort API exactly as you did before and get exactly the same behavior. If you do care, then you can opt in by adding on .nullsFirst() or .nullsLast() where you find it useful. This is intentionally designed so that it stays out of the way when you don't care about it and is quite minimal.

public record Sort<T>(String property,
boolean isAscending,
boolean ignoreCase,
Boolean orderNullsFirst) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I'm happy with Boolean here.

Because orderNullsFirst = false isn't completely obviously the same thing as "order nulls last".

I think an enum would be more appropriate, as in JPA.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering about that, too, when I wrote this up, whether it would be better for clarity to use an enum. I switched to an enum under 9af3253 and also included @since 1.1 which I had missed in my previous changes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a huge fan of increasing this class, what do you think of having components instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a huge fan of increasing this class, what do you think of having components instead?

@otaviojava I'm not sure what you mean by having components instead. From the other part of your comment, I am guess that you want the enum moved out of the Sort class. I liked it there because you can write Sort.Nulls.FIRST which reads very well, but if you prefer it moved to the same level as Sort, I could do that. I'm not sure if that is what you are asking for though.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to understand how big this Sort class can become, given that we want to put some Sort configurations in a single place.

What I would suggest is: instead of having it here, we could consider moving it to another class, such as SortNullable, and so on.

I understand we as a team want this option, but I recommend creating classes or specializations for any new configuration type rather than increasing this one.

What do you think?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The decision to represent Sort configuration as a Java record means that it cannot be subclassed with a SortNullable. That means if we create a SortNullable then it would not be an instance of Sort, and so it would not be usable in Order.by(Sort...), and then you need Order.by(SortNullable...) even though only one out of several items that the user supplies intends to sort a nullable entity attribute and the others should have been fine as just Sort but now need to be SortNullable since one of the other items is a SortNullable. It gets worse. Sorts are obtained from the metamodel and so then the metamodel needs a way to obtain a SortNullable for something you don't actually want to be nullable so that you can combine it with things that are nullable in Order.by(SortNullable...). The end user would need to do something like this:

Order.by(_Product.price.desc().nullsLast(), // this is fine
         _Product.name.asc().asSortNullable(), // confusing and annoying to user
         _Product.id.asc().asSortNullable()); // confusing and annoying to user

That is just one example of where the specialization makes the API uglier and more burdensome for users instead of better.

I also want to point out that you are rightly referring to Sort as a configuration. It is perfectly normal for configuration to include some options that not all users will take advantage of. It is unnatural to subclass or copy a configuration when you introduce a new configuration property.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, thank.

@gavinking
Copy link
Copy Markdown
Member

Null ordering is fundamentally non-portable across databases.

@otaviojava I think this is fine, as long as it's clear that support is not required. (And I think this PR already makes it clear.)

And this is definitely something people request and use.

Copy link
Copy Markdown

@FroMage FroMage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thanks.

@otaviojava otaviojava self-requested a review April 7, 2026 12:54
@otaviojava otaviojava dismissed their stale review April 7, 2026 12:55

based on discussion I iwll remove my hold

Copy link
Copy Markdown
Member

@gavinking gavinking left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a couple of @param javadocs which have periods (inconsistently).

Otherwise it's fine.

@otaviojava otaviojava merged commit cc35097 into jakartaee:main Apr 15, 2026
5 checks passed
njr-11 added a commit to njr-11/data that referenced this pull request Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Use Case]: Allow specifying how null values are sorted in Sort

4 participants