/** * Creates a new {@link OrderBySource} for the given clause, checking the property referenced exists on the given * type. * * @param clause must not be {@literal null}. * @param domainClass must not be {@literal null}. */ OrderBySource(String clause, Optional<Class<?>> domainClass) { this.orders = new ArrayList<>(); if (!StringUtils.hasText(clause)) { return; } for (String part : clause.split(BLOCK_SPLIT)) { Matcher matcher = DIRECTION_SPLIT.matcher(part); if (!matcher.find()) { throw new IllegalArgumentException(String.format(INVALID_ORDER_SYNTAX, part)); } String propertyString = matcher.group(1); String directionString = matcher.group(2); // No property, but only a direction keyword if (DIRECTION_KEYWORDS.contains(propertyString) && directionString == null) { throw new IllegalArgumentException(String.format(INVALID_ORDER_SYNTAX, part)); } this.orders.add(createOrder(propertyString, Direction.fromOptionalString(directionString), domainClass)); } }
/** * Parses the given sort expressions into a {@link Sort} instance. The implementation expects the sources to be a * concatenation of Strings using the given delimiter. If the last element can be parsed into a {@link Direction} it's * considered a {@link Direction} and a simple property otherwise. * * @param source will never be {@literal null}. * @param delimiter the delimiter to be used to split up the source elements, will never be {@literal null}. * @return */ Sort parseParameterIntoSort(String[] source, String delimiter) { List<Order> allOrders = new ArrayList<>(); for (String part : source) { if (part == null) { continue; } String[] elements = part.split(delimiter); Optional<Direction> direction = elements.length == 0 ? Optional.empty() : Direction.fromOptionalString(elements[elements.length - 1]); int lastIndex = direction.map(it -> elements.length - 1).orElseGet(() -> elements.length); for (int i = 0; i < lastIndex; i++) { toOrder(elements[i], direction).ifPresent(allOrders::add); } } return allOrders.isEmpty() ? Sort.unsorted() : Sort.by(allOrders); }