1515 */
1616package org .springframework .data .envers .repository .support ;
1717
18- import static org .springframework .data .history .RevisionMetadata .RevisionType .*;
19-
20- import java .util .ArrayList ;
21- import java .util .List ;
22- import java .util .Optional ;
23-
2418import jakarta .persistence .EntityManager ;
25-
2619import org .hibernate .Hibernate ;
2720import org .hibernate .envers .AuditReader ;
2821import org .hibernate .envers .AuditReaderFactory ;
3225import org .hibernate .envers .RevisionType ;
3326import org .hibernate .envers .query .AuditEntity ;
3427import org .hibernate .envers .query .AuditQuery ;
28+ import org .hibernate .envers .query .criteria .AuditProperty ;
3529import org .hibernate .envers .query .order .AuditOrder ;
3630import org .springframework .data .domain .Page ;
3731import org .springframework .data .domain .PageImpl ;
3832import org .springframework .data .domain .Pageable ;
33+ import org .springframework .data .domain .Sort ;
3934import org .springframework .data .history .AnnotationRevisionMetadata ;
4035import org .springframework .data .history .Revision ;
4136import org .springframework .data .history .RevisionMetadata ;
4843import org .springframework .transaction .annotation .Transactional ;
4944import org .springframework .util .Assert ;
5045
46+ import java .util .ArrayList ;
47+ import java .util .Collections ;
48+ import java .util .List ;
49+ import java .util .Optional ;
50+
51+ import static org .springframework .data .history .RevisionMetadata .RevisionType .*;
52+
5153/**
5254 * Repository implementation using Hibernate Envers to implement revision specific query methods.
5355 *
5860 * @author Julien Millau
5961 * @author Mark Paluch
6062 * @author Sander Bylemans
63+ * @author Niklas Loechte
6164 */
6265@ Transactional (readOnly = true )
6366public class EnversRevisionRepositoryImpl <T , ID , N extends Number & Comparable <N >>
@@ -70,14 +73,14 @@ public class EnversRevisionRepositoryImpl<T, ID, N extends Number & Comparable<N
7073 * Creates a new {@link EnversRevisionRepositoryImpl} using the given {@link JpaEntityInformation},
7174 * {@link RevisionEntityInformation} and {@link EntityManager}.
7275 *
73- * @param entityInformation must not be {@literal null}.
76+ * @param entityInformation must not be {@literal null}.
7477 * @param revisionEntityInformation must not be {@literal null}.
75- * @param entityManager must not be {@literal null}.
78+ * @param entityManager must not be {@literal null}.
7679 */
7780 public EnversRevisionRepositoryImpl (JpaEntityInformation <T , ?> entityInformation ,
78- RevisionEntityInformation revisionEntityInformation , EntityManager entityManager ) {
81+ RevisionEntityInformation revisionEntityInformation , EntityManager entityManager ) {
7982
80- Assert .notNull (revisionEntityInformation , "RevisionEntityInformation must not be null" );
83+ Assert .notNull (revisionEntityInformation , "RevisionEntityInformation must not be null! " );
8184
8285 this .entityInformation = entityInformation ;
8386 this .entityManager = entityManager ;
@@ -91,7 +94,7 @@ public Optional<Revision<N, T>> findLastChangeRevision(ID id) {
9194 .setMaxResults (1 ) //
9295 .getResultList ();
9396
94- Assert .state (singleResult .size () <= 1 , "We expect at most one result" );
97+ Assert .state (singleResult .size () <= 1 , "We expect at most one result. " );
9598
9699 if (singleResult .isEmpty ()) {
97100 return Optional .empty ();
@@ -104,14 +107,14 @@ public Optional<Revision<N, T>> findLastChangeRevision(ID id) {
104107 @ SuppressWarnings ("unchecked" )
105108 public Optional <Revision <N , T >> findRevision (ID id , N revisionNumber ) {
106109
107- Assert .notNull (id , "Identifier must not be null" );
108- Assert .notNull (revisionNumber , "Revision number must not be null" );
110+ Assert .notNull (id , "Identifier must not be null! " );
111+ Assert .notNull (revisionNumber , "Revision number must not be null! " );
109112
110113 List <Object []> singleResult = (List <Object []>) createBaseQuery (id ) //
111114 .add (AuditEntity .revisionNumber ().eq (revisionNumber )) //
112115 .getResultList ();
113116
114- Assert .state (singleResult .size () <= 1 , "We expect at most one result" );
117+ Assert .state (singleResult .size () <= 1 , "We expect at most one result. " );
115118
116119 if (singleResult .isEmpty ()) {
117120 return Optional .empty ();
@@ -133,15 +136,46 @@ public Revisions<N, T> findRevisions(ID id) {
133136 return Revisions .of (revisionList );
134137 }
135138
136- @ SuppressWarnings ("unchecked" )
137- public Page <Revision <N , T >> findRevisions (ID id , Pageable pageable ) {
138139
139- AuditOrder sorting = RevisionSort .getRevisionDirection (pageable .getSort ()).isDescending () //
140+ private AuditOrder mapRevisionSort (RevisionSort revisionSort ) {
141+
142+ return RevisionSort .getRevisionDirection (revisionSort ).isDescending () //
140143 ? AuditEntity .revisionNumber ().desc () //
141144 : AuditEntity .revisionNumber ().asc ();
145+ }
146+
147+ private List <AuditOrder > mapPropertySort (Sort sort ) {
148+
149+ if (sort .isEmpty ()) {
150+ return Collections .singletonList (AuditEntity .revisionNumber ().asc ());
151+ }
152+
153+ List <AuditOrder > result = new ArrayList <>();
154+ for (Sort .Order order : sort ) {
155+
156+ AuditProperty <Object > property = AuditEntity .property (order .getProperty ());
157+ AuditOrder auditOrder = order .getDirection ().isAscending () ?
158+ property .asc () :
159+ property .desc ();
160+
161+ result .add (auditOrder );
162+ }
163+
164+ return result ;
165+ }
166+
167+ @ SuppressWarnings ("unchecked" )
168+ public Page <Revision <N , T >> findRevisions (ID id , Pageable pageable ) {
169+
170+ AuditQuery baseQuery = createBaseQuery (id );
171+
172+ List <AuditOrder > orderMapped = (pageable .getSort () instanceof RevisionSort ) ?
173+ Collections .singletonList (mapRevisionSort ((RevisionSort ) pageable .getSort ())) :
174+ mapPropertySort (pageable .getSort ());
175+
176+ orderMapped .forEach (baseQuery ::addOrder );
142177
143- List <Object []> resultList = createBaseQuery (id ) //
144- .addOrder (sorting ) //
178+ List <Object []> resultList = baseQuery //
145179 .setFirstResult ((int ) pageable .getOffset ()) //
146180 .setMaxResults (pageable .getPageSize ()) //
147181 .getResultList ();
@@ -185,7 +219,7 @@ static class QueryResult<T> {
185219 Assert .notNull (data , "Data must not be null" );
186220 Assert .isTrue ( //
187221 data .length == 3 , //
188- () -> String .format ("Data must have length three, but has length %d" , data .length ));
222+ () -> String .format ("Data must have length three, but has length %d. " , data .length ));
189223 Assert .isTrue ( //
190224 data [2 ] instanceof RevisionType , //
191225 () -> String .format ("The third array element must be of type Revision type, but is of type %s" ,
@@ -201,7 +235,7 @@ RevisionMetadata<?> createRevisionMetadata() {
201235 return metadata instanceof DefaultRevisionEntity //
202236 ? new DefaultRevisionMetadata ((DefaultRevisionEntity ) metadata , revisionType ) //
203237 : new AnnotationRevisionMetadata <>(Hibernate .unproxy (metadata ), RevisionNumber .class , RevisionTimestamp .class ,
204- revisionType );
238+ revisionType );
205239 }
206240
207241 private static RevisionMetadata .RevisionType convertRevisionType (RevisionType datum ) {
0 commit comments