Browse Source

Fixed bug in OrderBySource.

OrderBySource can now take part in nested property resolving as well and correctly resolves properties containing a camel case letter.
pull/2/head
Oliver Gierke 15 years ago
parent
commit
312fad40e2
  1. 2
      spring-data-commons-core/src/main/java/org/springframework/data/domain/Sort.java
  2. 55
      spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/OrderBySource.java
  3. 3
      spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java
  4. 26
      spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/OrderBySourceUnitTests.java

2
spring-data-commons-core/src/main/java/org/springframework/data/domain/Sort.java

@ -192,7 +192,7 @@ public class Sort implements @@ -192,7 +192,7 @@ public class Sort implements
} catch (Exception e) {
throw new IllegalArgumentException(
String.format(
"Invalid value '%s' for orders given! Has to be either 'desc' or 'asc'.",
"Invalid value '%s' for orders given! Has to be either 'desc' or 'asc' (case insensitive).",
value), e);
}
}

55
spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/OrderBySource.java

@ -17,11 +17,12 @@ package org.springframework.data.repository.query.parser; @@ -17,11 +17,12 @@ package org.springframework.data.repository.query.parser;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ -36,45 +37,59 @@ import org.springframework.util.StringUtils; @@ -36,45 +37,59 @@ import org.springframework.util.StringUtils;
*/
public class OrderBySource {
private final String BLOCK_SPLIT = "(?<=Asc|Desc)(?=[A-Z])";
private final Pattern DIRECTION_SPLIT = Pattern.compile("(.+)(Asc|Desc)$");
private final List<Order> orders;
public OrderBySource(String clause) {
this(clause, null);
}
public OrderBySource(String clause, Class<?> domainClass) {
this.orders = new ArrayList<Sort.Order>();
List<String> properties = new ArrayList<String>();
for (String part : clause.split("(?<=[a-z])(?=[A-Z])")) {
for (String part : clause.split(BLOCK_SPLIT)) {
Direction direction = defaultedFrom(part);
Matcher matcher = DIRECTION_SPLIT.matcher(part);
if (direction == null) {
properties.add(StringUtils.uncapitalize(part));
} else {
Assert.notEmpty(
properties,
"Invalid order syntax! You have to provide at least one property before the sort direction.");
orders.addAll(Order.create(direction, properties));
properties.clear();
if (!matcher.find()) {
throw new IllegalArgumentException(String.format(
"Invalid order syntax for part %s!", part));
}
Direction direction = Direction.fromString(matcher.group(2));
this.orders.add(createOrder(matcher.group(1), direction,
domainClass));
}
}
/**
* Tries to resolve a {@link Direction} for the given {@link String}.
* Returns {@literal null} if resolving fails.
* Creates an {@link Order} instance from the given property source,
* direction and domain class. If the domain class is given, we will use it
* for nested property traversal checks.
*
* @param candidate
* @see Property#from(String, Class)
* @param propertySource
* @param direction
* @param domainClass can be {@literal null}.
* @return
*/
private Direction defaultedFrom(String candidate) {
private Order createOrder(String propertySource, Direction direction,
Class<?> domainClass) {
try {
return Direction.fromString(candidate);
} catch (IllegalArgumentException e) {
return null;
if (null == domainClass) {
return new Order(direction,
StringUtils.uncapitalize(propertySource));
}
Property property = Property.from(propertySource, domainClass);
return new Order(direction, property.toDotPath());
}

3
spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java

@ -71,7 +71,8 @@ public class PartTree implements Iterable<OrPart> { @@ -71,7 +71,8 @@ public class PartTree implements Iterable<OrPart> {
buildTree(parts[0], domainClass);
this.orderBySource =
parts.length == 2 ? new OrderBySource(parts[1]) : null;
parts.length == 2 ? new OrderBySource(parts[1], domainClass)
: null;
}

26
spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/OrderBySourceUnitTests.java

@ -40,11 +40,10 @@ public class OrderBySourceUnitTests { @@ -40,11 +40,10 @@ public class OrderBySourceUnitTests {
@Test
public void handlesSingleDirectionAndMultiplePropertiesCorrectly()
throws Exception {
public void handlesCamelCasePropertyCorrecty() throws Exception {
assertThat(new OrderBySource("LastnameUsernameDesc").toSort(),
is(new Sort(DESC, "lastname", "username")));
is(new Sort(DESC, "lastnameUsername")));
}
@ -63,4 +62,25 @@ public class OrderBySourceUnitTests { @@ -63,4 +62,25 @@ public class OrderBySourceUnitTests {
new OrderBySource("Desc");
}
@Test
public void usesNestedPropertyCorrectly() throws Exception {
OrderBySource source = new OrderBySource("BarNameDesc", Foo.class);
assertThat(source.toSort(), is(new Sort(new Order(DESC, "bar.name"))));
}
@SuppressWarnings("unused")
private class Foo {
private Bar bar;
}
@SuppressWarnings("unused")
private class Bar {
private String name;
}
}

Loading…
Cancel
Save