Skip to content

Instantly share code, notes, and snippets.

@bernardolopes8
Last active November 15, 2024 13:04
Show Gist options
  • Save bernardolopes8/cf04f49e1b64bd47576e7204601ef126 to your computer and use it in GitHub Desktop.
Save bernardolopes8/cf04f49e1b64bd47576e7204601ef126 to your computer and use it in GitHub Desktop.
Jersey Pagination, Sorting, and Filtering Example

Jersey Pagination, Sorting, and Filtering

This example is meant to show how these features can be added to a Jersey REST API and it's based on a gist by bowenwr.

Notes:

  • Filtering is not working at the DAO level but it's being correctly interpreted by the annotation
  • The use of limit and offset may not be the best practice when building pagination, please keep this in mind
package my.application.dao;
import java.util.List;
import my.application.entity.Book;
import my.application.restutil.RequestOptions;
public interface BookPersister {
List<Book> getBooks(RequestOptions requestOptions);
}
package my.application.dao;
import java.util.List;
import javax.persistence.EntityManagerFactory;
import my.application.entity.Book;
import my.application.restutil.RequestOptions;
public class BookPersisterBean implements BookPersister {
private EntityManagerFactory factory;
public BookPersisterBean(EntityManagerFactory factory) {
this.factory = factory;
}
@Override
public List<Book> getAll(RequestOptions requestOptions) {
return PaginatedQueryUtil.getResultsWithRequestOptions(this.factory, requestOptions, Book.class);
}
}
package my.application.ws;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import my.application.dao.BookPersister;
import my.application.dao.PersisterFactory;
import my.application.entity.Book;
import my.application.restutil.RequestOptions;
import my.application.restutil.RequestOptionsParams;
@Path("/books")
@Produces(MediaType.APPLICATION_JSON)
public class BookService {
@RequestOptionsParams RequestOptions requestOptions;
@GET
public Response getBooks() {
BookPersister persister = PersisterFactory.getInstance().getBookPersister();
List<Book> books = new ArrayList<>();
books = persister.getBooks(requestOptions);
String totalBooksCount = persister.getCount().toString();
return Response.ok().
entity(books).
header("X-Total-Count", totalBooksCount).
build();
}
}
package my.application.restutil;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.logging.Logger;
public class FieldsFactory {
public static final String PARAMS_FIELDS = "fields";
private static final Logger logger = Logger.getLogger(FieldsFactory.class.getName());
private FieldsFactory() {
}
public static Fields parse(final HttpServletRequest request) {
return parseFromParams(request);
}
public static Fields parseFromParams(final HttpServletRequest request) {
Fields fields = new Fields();
Enumeration<String> params = request.getParameterNames();
while (params.hasMoreElements()) {
String key = params.nextElement();
String value = request.getParameter(key);
if (key.equalsIgnoreCase(PARAMS_FIELDS)) {
String[] query = value.split(",");
for (String q : query) {
logger.fine("Adding " + q);
fields.addField(q);
}
}
}
return fields;
}
}
package my.application.restutil;
import java.util.ArrayList;
import java.util.List;
public class Filtering {
List<Key> filterList = new ArrayList<>();
public Filtering() {
}
public static Operator strToOperator(String op) {
if ("<".equals(op)) {
return Operator.LESS;
}
if ("<=".equals(op)) {
return Operator.LESS_EQUAL;
}
if ("=".equals(op)) {
return Operator.EQUAL;
}
if (">=".equals(op)) {
return Operator.GREATER_EQUAL;
}
if (">".equals(op)) {
return Operator.GREATER;
}
if ("!=".equals(op)) {
return Operator.NOT_EQUAL;
}
return null;
}
public void addFilter(String key, Operator operator, String value) {
System.out.println(new Key(key, operator, value));
filterList.add(new Key(key, operator, value));
}
public List<Key> fillterList() {
return filterList;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
for (Key k : filterList) {
str.append(k + ";");
}
return str.toString();
}
public enum Operator {
LESS("%3C"), LESS_EQUAL("%3C%3D"), EQUAL("%3D"), GREATER_EQUAL("%3E%3D"), GREATER("%3E"), NOT_EQUAL("%3C%3E");
private final String value;
Operator(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String toString() {
switch (this) {
case LESS:
return "<";
case LESS_EQUAL:
return "<=";
case EQUAL:
return "=";
case GREATER_EQUAL:
return ">=";
case GREATER:
return ">";
case NOT_EQUAL:
return "!=";
}
return "";
}
}
public class Key {
String key;
Operator operator;
String value;
public Key(String key, Operator operator, String value) {
this.key = key;
this.operator = operator;
this.value = value;
}
public String getKey() {
return key;
}
public Operator getOperator() {
return operator;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return getKey() + getOperator() + getValue();
}
}
}
package my.application.restutil;
import my.application.restutil.Filtering.Operator;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.logging.Logger;
public class FilteringFactory {
public static final String PARAMS_FILTER = "filter";
private static final Logger logger = Logger.getLogger(FilteringFactory.class.getName());
private FilteringFactory() {
}
public static Filtering parse(final HttpServletRequest request) {
return parseFromParams(request);
}
public static Filtering parseFromParams(final HttpServletRequest request) {
Filtering filtering = new Filtering();
Enumeration<String> params = request.getParameterNames();
while (params.hasMoreElements()) {
String key = params.nextElement();
String value = request.getParameter(key);
if (key.equalsIgnoreCase(PARAMS_FILTER)) {
String[] query = value.split(",");
for (String q : query) {
logger.fine(q + ";" + Operator.EQUAL.toString() + "----" + q.indexOf(Operator.EQUAL.toString()));
int index = -1;
String k = null;
String v = null;
Operator op = null;
if ((index = q.indexOf(Operator.NOT_EQUAL.toString())) > -1) {
op = Operator.NOT_EQUAL;
k = q.substring(0, index);
v = q.substring(index + op.toString().length());
} else if ((index = q.indexOf(Operator.LESS_EQUAL.toString())) > -1) {
op = Operator.LESS_EQUAL;
k = q.substring(0, index);
v = q.substring(index + op.toString().length());
} else if ((index = q.indexOf(Operator.GREATER_EQUAL.toString())) > -1) {
op = Operator.GREATER_EQUAL;
k = q.substring(0, index);
v = q.substring(index + op.toString().length());
} else if ((index = q.indexOf(Operator.LESS.toString())) > -1) {
op = Operator.LESS;
k = q.substring(0, index);
v = q.substring(index + op.toString().length());
} else if ((index = q.indexOf(Operator.GREATER.toString())) > -1) {
op = Operator.GREATER;
k = q.substring(0, index);
v = q.substring(index + op.toString().length());
} else if ((index = q.indexOf(Operator.EQUAL.toString())) > -1) {
op = Operator.EQUAL;
k = q.substring(0, index);
v = q.substring(index + op.toString().length());
}
filtering.addFilter(k, op, v);
}
}
}
return filtering;
}
}
package my.application.ws;
import javax.inject.Inject;
import javax.ws.rs.ApplicationPath;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.ResourceConfig;
import my.application.restutil.PaginationExceptionMapper;
import my.application.restutil.RequestOptionsInjectionBinder;
import my.application.restutil.RequestOptionsResponseFilter;
@ApplicationPath("/v1/*")
public class MyWSApplication extends ResourceConfig {
@Inject
public MyWSApplication(ServiceLocator serviceLocator) {
// This won't run by itself, do things like map your service packages, object mapper, injection, etc.
// Register your filter for putting request options in the response
register(RequestOptionsResponseFilter.class);
// Exception mapper for pagination
register(PaginationExceptionMapper.class);
// Injection binder for putting RequestOptions into our services
register(new RequestOptionsInjectionBinder());
packages("my.application.ws");
}
}
package my.application.dao;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.metamodel.SingularAttribute;
import my.application.restutil.RequestOptions;
public class PaginatedQueryUtil {
public static <T> List<T> getResultsWithRequestOptions(EntityManagerFactory emf, RequestOptions requestOptions, Class<T> resultClass) {
EntityManager em = emf.createEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<T> query = builder.createQuery(resultClass);
Root<T> root = query.from(resultClass);
if (requestOptions != null && requestOptions.getSorting() != null)
{
String field = requestOptions.getSorting().getField();
String order = requestOptions.getSorting().getOrder();
Metamodel metamodel = em.getMetamodel();
EntityType<T> T_ = metamodel.entity(resultClass);
Set<String> sorteableFields = new HashSet<>(); // Fields who admit sorting
for (SingularAttribute<?, ?> sa : T_.getSingularAttributes()) {
if (!isClassCollection(sa.getJavaType())) sorteableFields.add(sa.getName()); // Collections get saved as blobs and thus can't be sorted
}
if (sorteableFields.stream().anyMatch(x -> x.equalsIgnoreCase(field))) {
if (order.equalsIgnoreCase("ASC")) query.orderBy(builder.asc(root.get(T_.getSingularAttribute(field))));
else query.orderBy(builder.desc(root.get(T_.getSingularAttribute(field))));
}
}
TypedQuery<T> typedQuery = em.createQuery(query);
if (requestOptions != null && requestOptions.getPagination() != null) {
typedQuery.setFirstResult(requestOptions.getPagination().getLimit() * requestOptions.getPagination().getOffset());
typedQuery.setMaxResults(requestOptions.getPagination().getLimit());
}
List<T> l = typedQuery.getResultList();
em.close();
return l;
}
// From https://stackoverflow.com/a/2651654/5502785
private static boolean isClassCollection(Class<?> c) {
return Collection.class.isAssignableFrom(c) || Map.class.isAssignableFrom(c);
}
}
package my.application.restutil;
public class Pagination {
private int limit;
private int offset;
private int total = -1;
public Pagination(int offset, int limit) {
this(offset, limit, 0);
}
public Pagination(int offset, int limit, int total) {
this.limit = limit;
this.offset = offset;
this.total = total;
}
public int getOffset() {
return offset;
}
public int getLimit() {
return limit;
}
public int getTotal() {
return total;
}
@Override
public String toString() {
return "Pagination { limit: " + limit + ", offset: " + offset + (total == -1 ? "" : (", total available records: " + total)) + "}";
}
}
package my.application.restutil;
import javax.ws.rs.WebApplicationException;
@SuppressWarnings("serial")
public class PaginationException extends WebApplicationException {
public PaginationException(String message) {
super(message);
}
public PaginationException(String message, Exception e) {
super(message, e);
}
}
package my.application.restutil;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
@Provider
public class PaginationExceptionMapper implements ExceptionMapper<PaginationException> {
@Override
public Response toResponse(PaginationException exception) {
// Maps a pagination exception to a HTTP 400 (meaning the client provided bad info such as non-numeric values)
return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()).type(MediaType.TEXT_PLAIN).build();
}
}
package my.application.restutil;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.logging.Logger;
public class PaginationFactory {
public static final int MAXIMUM_LIMIT = 100;
public static final int DEFAULT_LIMIT = 25;
public static final int DEFAULT_OFFSET = 0;
public static final String PARAMS_OFFSET = "offset";
public static final String PARAMS_LIMIT = "limit";
public static final String HEADER_LIMIT = "X-Limit";
public static final String HEADER_OFFSET = "X-Offset";
public static final String HEADER_TOTAL_RECORDS = "X-Total-Records";
private static final Logger logger = Logger.getLogger(PaginationFactory.class.getName());
private PaginationFactory() {
}
public static Pagination parse(final HttpServletRequest request) {
Pagination p = null;
if (request.getParameterMap().containsKey(PARAMS_OFFSET) || request.getParameterMap().containsKey(PARAMS_LIMIT)) {
p = parseFromParams(request);
} else {
p = parseFromHeaders(request);
}
return p;
}
private static Pagination parseFromHeaders(final HttpServletRequest request) {
boolean isOffsetInitialized = false;
boolean isLimitInitialized = false;
int offset = DEFAULT_OFFSET;
int limit = DEFAULT_LIMIT;
Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String key = headers.nextElement();
String value = request.getHeader(key);
if (key.equalsIgnoreCase(HEADER_OFFSET) && (!isOffsetInitialized)) {
try {
offset = Integer.parseInt(value);
if (offset < DEFAULT_OFFSET || limit > MAXIMUM_LIMIT) {
logger.fine("Offset exceeded acceptable range (>= {" + DEFAULT_OFFSET + "}). Offset was {"
+ value + "}");
throw new PaginationException(PARAMS_OFFSET + " exceeded acceptable range (>= " + DEFAULT_OFFSET
+ "). " + PARAMS_OFFSET + " was " + value);
}
isOffsetInitialized = true;
} catch (NumberFormatException | NullPointerException e) {
logger.fine("Error parsing offset from {} " + value + ", " + e);
throw new PaginationException("Error parsing " + PARAMS_OFFSET + " from supplied value: " + value);
}
} else if (key.equalsIgnoreCase(HEADER_LIMIT) && (!isLimitInitialized)) {
try {
limit = Integer.parseInt(value);
if (limit < 1 || limit > MAXIMUM_LIMIT) {
logger.fine("Limit exceeded acceptable range (1 - {" + MAXIMUM_LIMIT + "}). Limit was {" + value
+ "}");
throw new PaginationException(PARAMS_LIMIT + " exceeded acceptable range (1 - " + MAXIMUM_LIMIT
+ "). Supplied " + PARAMS_LIMIT + " was " + value);
}
isLimitInitialized = true;
} catch (NumberFormatException | NullPointerException e) {
logger.fine("Error parsing limit from {}" + value + "," + e);
throw new PaginationException("Error parsing " + PARAMS_LIMIT + " from supplied value: " + value);
}
}
}
if (isOffsetInitialized || isLimitInitialized) {
return new Pagination(offset, limit);
}
return null;
}
public static Pagination parseFromParams(final HttpServletRequest request) {
boolean isOffsetInitialized = false;
boolean isLimitInitialized = false;
int offset = DEFAULT_OFFSET;
int limit = DEFAULT_LIMIT;
Enumeration<String> params = request.getParameterNames();
while (params.hasMoreElements()) {
String key = params.nextElement();
String value = request.getParameter(key);
if (key.equalsIgnoreCase(PARAMS_OFFSET) && (!isOffsetInitialized)) {
try {
offset = Integer.parseInt(value);
if (offset < DEFAULT_OFFSET || limit > MAXIMUM_LIMIT) {
logger.fine("Offset exceeded acceptable range (>= {" + DEFAULT_OFFSET + "}). Offset was {"
+ value + "}");
throw new PaginationException(PARAMS_OFFSET + " exceeded acceptable range (>= " + DEFAULT_OFFSET
+ "). " + PARAMS_OFFSET + " was " + value);
}
isOffsetInitialized = true;
} catch (NumberFormatException | NullPointerException e) {
logger.fine("Error parsing offset from {} " + value + ", " + e);
throw new PaginationException("Error parsing " + PARAMS_OFFSET + " from supplied value: " + value);
}
} else if (key.equalsIgnoreCase(PARAMS_LIMIT) && (!isLimitInitialized)) {
try {
limit = Integer.parseInt(value);
if (limit < 1 || limit > MAXIMUM_LIMIT) {
logger.fine("Limit exceeded acceptable range (1 - {" + MAXIMUM_LIMIT + "}). Limit was {" + value
+ "}");
throw new PaginationException(PARAMS_LIMIT + " exceeded acceptable range (1 - " + MAXIMUM_LIMIT
+ "). Supplied " + PARAMS_LIMIT + " was " + value);
}
isLimitInitialized = true;
} catch (NumberFormatException | NullPointerException e) {
logger.fine("Error parsing limit from {}" + value + "," + e);
throw new PaginationException("Error parsing " + PARAMS_LIMIT + " from supplied value: " + value);
}
}
}
if (isOffsetInitialized || isLimitInitialized) {
return new Pagination(offset, limit);
}
return null;
}
}
package my.application.restutil;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.client.Invocation;
import java.util.Iterator;
import java.util.Map;
public class RequestOptions {
public static final String HEADER_RECURSION = "X-Recursion";
public static final String RECURSION_ENABLED = "true";
public static final String RECURSION_DISABLED = "false";
private Pagination pagination = null;
private Filtering filtering = null;
private boolean recursive = false;
private Fields fields = null;
private Sorting sorting = null;
public RequestOptions() {
}
public RequestOptions(HttpServletRequest request) {
parse(request);
}
public Pagination getPagination() {
return pagination;
}
public Filtering getFiltering() {
return filtering;
}
public Fields getFields() {
return fields;
}
public boolean isRecursive() {
return recursive;
}
public Sorting getSorting() {
return sorting;
}
public Invocation.Builder apply(Invocation.Builder builder) {
if (pagination != null) {
builder.header(PaginationFactory.HEADER_OFFSET, pagination.getOffset());
builder.header(PaginationFactory.HEADER_LIMIT, pagination.getLimit());
}
return builder;
}
public RequestOptions parse(final HttpServletRequest request) {
String recursion = request.getHeader(HEADER_RECURSION);
if (recursion != null && recursion.trim().equalsIgnoreCase(RECURSION_ENABLED)) {
recursive = true;
} else {
for (Iterator<Map.Entry<String, String[]>> iterator = request.getParameterMap().entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<String, String[]> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue()[0];
if (key.equalsIgnoreCase("recursive") && value.trim().equalsIgnoreCase(RECURSION_ENABLED)) {
recursive = true;
}
}
}
this.pagination = PaginationFactory.parse(request);
this.filtering = FilteringFactory.parse(request);
this.fields = FieldsFactory.parse(request);
this.sorting = SortingFactory.parse(request);
return this;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
if (pagination != null) {
str.append("Request Options: {" + pagination.toString() + ", Recursion: " + recursive + "}\n");
} else {
str.append("No pagination defined\n");
}
if (filtering != null) {
str.append("Request Options: {" + filtering.toString() + ", Recursion: " + recursive + "}\n");
} else {
str.append("No filtering defined\n");
}
if (sorting != null) {
str.append("Request Options: {" + sorting.toString() + ", Recursion: " + recursive + "}\n");
} else {
str.append("No sorting defined\n");
}
return str.toString();
}
}
package my.application.restutil;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import javax.inject.Singleton;
public final class RequestOptionsInjectionBinder extends AbstractBinder {
/**
* Implement to provide binding definitions using the exposed binding
* methods.
*/
@Override
protected void configure() {
System.out.println("injectionbinder");
bindFactory(RequestOptionsValueFactory.class).to(RequestOptions.class)
.proxy(true).proxyForSameScope(false).in(RequestScoped.class);
bind(RequestOptionsInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<RequestOptionsParams>>() {
})
.in(Singleton.class);
}
}
package my.application.restutil;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import javax.inject.Inject;
import javax.inject.Named;
public class RequestOptionsInjectionResolver implements InjectionResolver<RequestOptionsParams> {
@Inject
@Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
InjectionResolver<Inject> systemInjectionResolver;
@Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
if (RequestOptions.class == injectee.getRequiredType()) {
return systemInjectionResolver.resolve(injectee, handle);
}
return null;
}
@Override
public boolean isConstructorParameterIndicator() {
return false;
}
@Override
public boolean isMethodParameterIndicator() {
return false;
}
}
package my.application.restutil;
import java.lang.annotation.*;
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestOptionsParams {
}
package my.application.restutil;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import java.util.logging.Logger;
public class RequestOptionsResponseFilter implements ContainerResponseFilter {
private static final Logger logger = Logger.getLogger(RequestOptionsResponseFilter.class.getName());
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
// System.out.println("Filter...");
if (requestContext.getProperty("requestOptions") != null && (requestContext.getProperty("requestOptions") instanceof RequestOptions)) {
RequestOptions requestOptions = (RequestOptions) requestContext.getProperty("requestOptions");
if (requestOptions.getPagination() != null) {
logger.finer("Adding pagination information to response: {}" + requestOptions.getPagination());
// responseContext.getHeaders().add(Pagination.HEADER_TOTAL_RECORDS, requestOptions.getPagination().getTotal());
// responseContext.getHeaders().add(Pagination.HEADER_LIMIT, requestOptions.getPagination().getLimit());
// responseContext.getHeaders().add(Pagination.HEADER_OFFSET, requestOptions.getPagination().getOffset());
responseContext.getHeaders().add(PaginationFactory.HEADER_TOTAL_RECORDS, requestOptions.getPagination().getTotal());
responseContext.getHeaders().add(PaginationFactory.PARAMS_LIMIT, requestOptions.getPagination().getLimit());
responseContext.getHeaders().add(PaginationFactory.PARAMS_OFFSET, requestOptions.getPagination().getOffset());
}
}
}
}
package my.application.restutil;
import org.glassfish.hk2.api.Factory;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
/**
* Factory implementation for resolving request-based attributes and other
* information.
*/
public class RequestOptionsValueFactory implements Factory<RequestOptions> {
@Context
private ResourceContext context;
@Override
public RequestOptions provide() {
final HttpServletRequest request = context.getResource(HttpServletRequest.class);
return new RequestOptions(request);
}
@Override
public void dispose(RequestOptions instance) {
}
}
package my.application.restutil;
public class Sorting {
private String field;
private String order;
public Sorting(String field, String order) {
this.field = field;
this.order = order;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
@Override
public String toString() {
return "Sorting { by: " + field + ", order: " + order + "}";
}
}
package my.application.restutil;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
// import java.util.logging.Logger;
public class SortingFactory {
public static final String PARAMS_SORT = "sort";
public static final String PARAMS_ORDER = "order";
public static final String DEFAULT_ORDER = "ASC";
// private static final Logger logger = Logger.getLogger(SortingFactory.class.getName());
private SortingFactory() {
}
public static Sorting parse(final HttpServletRequest request) {
Sorting s = null;
if (request.getParameterMap().containsKey(PARAMS_SORT)) {
s = parseFromParams(request);
}
return s;
}
public static Sorting parseFromParams(final HttpServletRequest request) {
boolean isSortDefined = false;
boolean isOrderDefined = false;
String sort = null;
String order = DEFAULT_ORDER;
Enumeration<String> params = request.getParameterNames();
while (params.hasMoreElements()) {
String key = params.nextElement();
String value = request.getParameter(key);
if (key.equalsIgnoreCase(PARAMS_SORT) && (!isSortDefined)) {
sort = value;
isSortDefined = true;
} else if (key.equalsIgnoreCase(PARAMS_ORDER) && (!isOrderDefined)) {
if (value.equalsIgnoreCase("DESC") || value.equalsIgnoreCase("ASC")) {
order = value;
}
isOrderDefined = true;
}
}
if (isSortDefined) {
return new Sorting(sort, order);
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment