Автоматическая сортировка отображаемых коллекций типа Set и Map любым компаратором с помощью аннотации @SortComparator

Если отображаемый класс содержит поля типа SortedMap или SortedSet, то их можно пометить аннотацией @SortComparator. И тогда после выборки данных из БД они будут отсортированы с помощью заданного java-компаратора и будут доступны в этих полях уже в отсортированном виде.

Отметим, что при таком подходе сортировка будет проведена в java-приложении. Если нужна сортировка выборки на стороне БД, то это делается аннотациями @javax.persistence.annotations.OrderBy или @org.hibernate.annotations.OrderBy.

Подготовка

Создадим базовое веб-приложения на связке Spring Boot 3 + Hibernate + PostgreSQL

Убедитесь, что файле /src/main/resources/application.properties есть следующая строка, позволяющая Hibernate’у автоматически создавать (и обновлять) схему БД при запуске приложения на основании аннотаций в классах предметной области:

spring.jpa.hibernate.ddl-auto=update

Код

Напишем компаратор, который будет сортировать строки нужным нам образом:

Данный компаратор сортирует адреса электронной почты таким образом, что сначала идут адреса у которых имя домена идёт выше по алфавиту. А если имена доменов совпадают, то внутри такой группы адреса идут просто в алфавитном порядке.

То есть получается что-то вроде: x@a.ru, z@a.ru, a@b.ru, b@b.ru. Домен a.ru выше по алфавиту, поэтому адреса с этим доменом в начале списка.

Далее создадим класс предметной области, содержащий поле типа SortedSet<String>:

Мы помечаем поле SortedSet<String> emails аннотацией @org.hibernate.annotations.SortComparator в которую передаём параметром класс нашего компаратора. Имя аннотации пишем целиком, так как это специфичная Hibernate аннотация, не являющаяся частью JPA.

Создадим репозиторий с кастомным запросом, который будет делать выборку из двух таблиц: PERSON и из связанной с ней таблицы EMAILS:

Напишем тест, который продемонстрирует работу нашего кода:

В данном тесте мы помещаем адреса электронной почты в SortedSet в произвольном порядке. Поскольку SortedSet имплементирован TreeSet’ом, мы знаем, что внутри себя это множество автоматически упорядочивается в простом алфавитном порядке (и мы это увидим). Но после сохранения в БД и выборки, мы видим, что данные отсортированы нашим компаратором, то есть сначала идут адреса с доменом @mail.ru, а затем два адреса с доменом @russia.ru.

Сравним порядок полученных данных с тем, как они хранятся в БД:

И действительно в БД адреса сохранились в простом алфавитном порядке, как и положено данным последовательно взятым из TreeSet<String>. Но при выборке, как мы увидели в тесте, данные сортируются нашим кастомным компаратором.