12

We are using a very simple setup of @RepositoryRestResource on top of a PagingAndSortingRepository connected to a postgres database. Also we have configured spring.jackson.property-naming-strategy=SNAKE_CASE to return pretty json. It was all fine and dandy until we started sorting. As we have discovered - sorting requires us to provide the actual class field names (which we of course have in camel case):

get("/thing?sort=dateCreated,desc")

And when we try to do javascript friendly

get("/thing?sort=date_created,desc")

it fails miserably because jpa tries to split the parameter by the underscore.

Is there a simple way to have the path params the same format as we have them in the json that we are returning?

3
  • Did you try __ (2 underscores)? (see stackoverflow.com/questions/29983047/…) Commented Nov 24, 2016 at 17:37
  • Yep and that did not work either. Seems that __ is just for custom methods. Commented Nov 24, 2016 at 17:45
  • Tried to reproduce it but it works fine -> code on github. What versions are you using? Commented Nov 26, 2016 at 0:37

3 Answers 3

10
+50

There is a bug for this - DATAREST-883. It was fixed and released. But then, due to regressions (DATAREST-909) this has been dropped in the very next release. I asked them on Github if they plan to have this again as this has bitten me in the past as well. We'll see what they have to say about this.

For now you can:

  • leave it be
  • go with the camel case property names
  • work around this (e.g. go with Alan Haye's answer) - this seems fragile IMHO, but probably will do in a short term.

The status of the feature in the spring-boot versions I've tested with:

  • 1.4.0 (spring-data-rest 2.5.2): not yet implemented
  • 1.4.1 (spring-data-rest 2.5.3): works -> code
  • 1.4.2 (spring-data-rest 2.5.5): dropped
Sign up to request clarification or add additional context in comments.

3 Comments

Wow, thanks for the investigation! We will wait until it is fixed :)
It looks like this is still an issue as of sdr 3.4.6 ...
Still open as per this issue.
4

It is unclear whether you can do this in some Spring Data Rest specific way however you should be able to handle it by means of a standard Servlet filter which would look something like the below:

public class SortParameterConversionFilter extends GenericFilterBean {

    // as we are extending Spring's GenericFilterBean
    // you can then *possibly* inject the RepositoryRestConfiguration
    // and use  RepositoryRestConfiguration#getSortParamName
    // to avoid hard coding
    private static final String SORT_PARAM_KEY = "sort";

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        if (shouldApply(request)) {
            chain.doFilter(new CollectionResourceRequestWrapper(request), res);
        } else {
            chain.doFilter(req, res);
        }
    }

    /**
     * 
     * @param request
     * @return True if this filter should be applied for this request, otherwise
     *         false.
     */
    protected boolean shouldApply(HttpServletRequest request) {
        return request.getServletPath().matches("some-pattern");
    }

    /**
     * HttpServletRequestWrapper implementation which allows us to wrap and
     * modify the incoming request.
     *
     */
    public class CollectionResourceRequestWrapper extends HttpServletRequestWrapper {

        public ResourceRequestWrapper(HttpServletRequest request) {
            super(request);
        }

        @Override
        public String getParameter(final String name) {
            if (name.equals(SORT_PARAM_KEY)) {
                String [] parts = super.getParameter(SORT_PARAM_KEY).split(",");
                StringBuilder builder = new StringBuilder();

                int index = 0;

                for (String part : parts) {
                    // using some mechanism of you choosing
                    // convert from underscore to camelCase
                    // Using the Guava library for example
                    String convertedPart = CaseFormat.LOWER_UNDERSCORE.to(
                         CaseFormat.LOWER_CAMEL, part);
                    ++index;
                    builder.append(convertedPart).append(index < parts.length ? "," : "");
                }

                return builder.toString();
            }

            return super.getParameter(name);
        }
    }
}

1 Comment

In my case, I need to use getParameterValues instead getParameter
0

In situations, where in

  • all field names use Camel Casing in the Entity model
  • all entity fields have mapped JsonProperty names which use Snake Casing or have "spring.jackson.property-naming-strategy=SNAKE_CASE" enabled in configuration
  • Have very few (2/3) JsonProperty names with underscores and those are used in sort order list
  • Do not have multiple other entities facing same issue cause their JsonProperty names with underscores are not used in sort order

Then below code could be used as quick fix with not much impact on perf

 @Override
public Page< <YourEntity> > retrieveSortedList(Pageable pageable) {
Sort sortConditions = pageable.getSort();
         if (!sortConditions.isEmpty()) {
             List<Sort.Order> orderList = sortConditions.stream().toList();
             String curatedFieldName = "";
             List<Sort.Order> sortOrderList = new ArrayList<>();
             for (Sort.Order sortOrderObj : orderList) {
                 if (sortOrderObj.getProperty().contains("_")) {
                     String[] fieldParts = sortOrderObj.getProperty().split("_");
                     curatedFieldName = fieldParts[0];
                     for (int i = 1; i < fieldParts.length; i++) {
                         curatedFieldName += StringUtils.capitalize(fieldParts[i]);
                     }
                     Sort.Direction sortDirection = sortOrderObj.getDirection();
                     sortOrderList.add(new Sort.Order(sortDirection, curatedFieldName));
                 }
             }
             Sort sort = Sort.by(sortOrderList);
             Pageable modifiedPageable = PageRequest.of(pageable.getPageNumber(),
                     pageable.getPageSize(), sort);
             return <YourEntity>Repository.findAll(modifiedPageable);
         }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.