Reputation: 12740
My repository allows for sorting on any column when retrieving a list of users:
public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
@Query("SELECT u FROM User u")
public Page<User> all(Pageable page);
}
The trouble is that a user has some properties that cannot offer sorting, like his confirmedEmail
property.
@Entity
@Table(name = "user_account")
@SequenceGenerator(name = "id_generator", sequenceName = "user_account_id_seq", allocationSize = 10)
public class User extends AbstractEntity {
@Column(nullable = false)
private String firstname;
@Column(nullable = false)
private String lastname;
@Column(nullable = false, unique = true)
private EmailAddress email;
@Column(nullable = false)
private boolean confirmedEmail;
}
How can I prevent the Pageable
argument from sorting on this boolean confirmedEmail
property ?
I stumbled upon this issue when I sorted by clicking on the Confirmed
header in my Angular
data table.
This front-end event triggered the following request:
SELECT u FROM com.thalasoft.user.data.jpa.domain.User u order by u.confirmed asc
I know I can make this data table column not sortable, and I did. But I'd like to also have a server side safety in place.
As a side note, I wonder if I could also provide a default sorting if none is specified in the client request.
UPDATE: I created the utility method:
public static final Sort stripColumnsFromSorting(Sort sort, Set<String> nonSortableColumns) {
return Sort.by(sort.stream().filter(order -> {
return !nonSortableColumns.contains(order.getProperty());
}).collect(Collectors.toList()));
}
which I call like:
Set<String> nonSortableColumns = new HashSet<String>(Arrays.asList("id", "confirmedEmail"));
public ResponseEntity<PagedResources<UserResource>> all(@PageableDefault(sort = { "lastname", "firstname" }, direction = Sort.Direction.ASC) Pageable pageable, Sort sort,
PagedResourcesAssembler<User> pagedResourcesAssembler, UriComponentsBuilder builder) {
sort = CommonUtils.stripColumnsFromSorting(sort, nonSortableColumns);
userService.addSortToPageable(pageable, sort);
But it is still invoking the sorting on the non sortable column:
Invoking 'com.thalasoft.user.rest.controller.UserController.all' with arguments [Page request [number: 0, size 5, sort: confirmedEmail: DESC], confirmedEmail: DESC, org.springframework.data.web.MethodParameterAwarePagedResourcesAssembler@78817e7e, org.springframework.web.servlet.support.ServletUriComponentsBuilder@3e49647a]
Upvotes: 4
Views: 4820
Reputation: 30289
I think you can check Pageable argument of your controller method and then remove from it unnecessary fields, something like this:
public ResponseEntity<?> myControllerMethod(..., Pageable page) {
Sort newSort = Sort.by(page.getSort()
.get()
.filter(order -> !order.getProperty().equals("confirmedEmail"))
.collect(Collectors.toList()));
PageRequest newPage = PageRequest.of(page.getPageNumber(), page.getPageSize(), newSort);
// using newPage instead of page...
}
To specify a default order you can use @PageableDefault
annotation, for example:
public ResponseEntity<?> myControllerMethod(..., @PageableDefault(sort = "lastname", direction = ASC) Pageable page) {
//...
}
Upvotes: 3