Browse Source

DATACMNS-45 - Improved property handling in TypeDiscoverer and Property.

TypeDiscoverer now looks up property type using a PropertyDescriptor if no field with the given name can be found. Property now handles _-prefixed properties as well.
pull/2/head
Oliver Gierke 15 years ago
parent
commit
351e37e4eb
  1. 17
      spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Property.java
  2. 47
      spring-data-commons-core/src/main/java/org/springframework/data/util/TypeDiscoverer.java
  3. 18
      spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PropertyUnitTests.java
  4. 24
      spring-data-commons-core/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java

17
spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Property.java

@ -15,8 +15,9 @@ @@ -15,8 +15,9 @@
*/
package org.springframework.data.repository.query.parser;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -32,8 +33,9 @@ import org.springframework.util.StringUtils; @@ -32,8 +33,9 @@ import org.springframework.util.StringUtils;
* @author Oliver Gierke
*/
public class Property {
private static String ERROR_TEMPLATE = "No property %s found for type %s";
private static final Pattern SPLITTER = Pattern.compile("(?:_?(_*?[^_]+))");
private static final String ERROR_TEMPLATE = "No property %s found for type %s";
private final String name;
private final TypeInformation<?> type;
@ -228,8 +230,15 @@ public class Property { @@ -228,8 +230,15 @@ public class Property {
}
private static Property from(String source, TypeInformation<?> type) {
List<String> iteratorSource = new ArrayList<String>();
Matcher matcher = SPLITTER.matcher("_" + source);
while (matcher.find()) {
iteratorSource.add(matcher.group(1));
}
Iterator<String> parts = Arrays.asList(source.split("_")).iterator();
Iterator<String> parts = iteratorSource.iterator();
Property result = null;
Property current = null;

47
spring-data-commons-core/src/main/java/org/springframework/data/util/TypeDiscoverer.java

@ -17,9 +17,11 @@ package org.springframework.data.util; @@ -17,9 +17,11 @@ package org.springframework.data.util;
import static org.springframework.util.ObjectUtils.*;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
@ -28,6 +30,7 @@ import java.util.List; @@ -28,6 +30,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@ -159,15 +162,51 @@ class TypeDiscoverer<S> implements TypeInformation<S> { @@ -159,15 +162,51 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
return info == null ? null : info.getProperty(fieldname.substring(separatorIndex + 1));
}
/**
* Returns the {@link TypeInformation} for the given atomic field. Will inspect fields first and return the type of a
* field if available. Otherwise it will fall back to a {@link PropertyDescriptor}.
*
* @see #getGenericType(PropertyDescriptor)
* @param fieldname
* @return
*/
private TypeInformation<?> getPropertyInformation(String fieldname) {
Class<?> type = getType();
Field field = ReflectionUtils.findField(type, fieldname);
Field field = ReflectionUtils.findField(getType(), fieldname);
if (field != null) {
return createInfo(field.getGenericType());
}
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(type, fieldname);
if (field == null) {
return descriptor == null ? null : createInfo(getGenericType(descriptor));
}
/**
* Returns the generic type for the given {@link PropertyDescriptor}. Will inspect its read method
* followed by the first parameter of the write method.
*
* @param descriptor must not be {@literal null}
* @return
*/
private static Type getGenericType(PropertyDescriptor descriptor) {
Method method = descriptor.getReadMethod();
if (method != null) {
return method.getGenericReturnType();
}
method = descriptor.getWriteMethod();
if (method == null) {
return null;
}
return createInfo(field.getGenericType());
Type[] parameterTypes = method.getGenericParameterTypes();
return parameterTypes.length == 0 ? null : parameterTypes[0];
}
/*

18
spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PropertyUnitTests.java

@ -71,7 +71,7 @@ public class PropertyUnitTests { @@ -71,7 +71,7 @@ public class PropertyUnitTests {
@Test
public void prfersExplicitPaths() throws Exception {
public void prefersExplicitPaths() throws Exception {
Property reference = Property.from("user_name", Sample.class);
assertThat(reference.getName(), is("user"));
@ -130,9 +130,24 @@ public class PropertyUnitTests { @@ -130,9 +130,24 @@ public class PropertyUnitTests {
Property from = Property.from("barUserName", Sample.class);
}
/**
* @see DATACMNS-45
*/
@Test
public void handlesEmptyUnderscoresCorrectly() {
Property property = Property.from("_foo", Sample2.class);
assertThat(property.getName(), is("_foo"));
assertThat(property.getType(), is(typeCompatibleWith(Foo.class)));
property = Property.from("_foo__email", Sample2.class);
assertThat(property.toDotPath(), is("_foo._email"));
}
private class Foo {
String userName;
String _email;
}
private class Bar {
@ -159,5 +174,6 @@ public class PropertyUnitTests { @@ -159,5 +174,6 @@ public class PropertyUnitTests {
private String userNameWhatever;
private FooBar user;
private Foo _foo;
}
}

24
spring-data-commons-core/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java

@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
*/
package org.springframework.data.util;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.Calendar;
@ -134,6 +134,20 @@ public class ClassTypeInformationUnitTests { @@ -134,6 +134,20 @@ public class ClassTypeInformationUnitTests {
assertFalse(first.getProperty("wrapped").equals(second.getProperty("wrapped")));
}
@Test
public void handlesPropertyFieldMismatchCorrectly() {
TypeInformation<PropertyGetter> from = ClassTypeInformation.from(PropertyGetter.class);
TypeInformation<?> property = from.getProperty("_name");
assertThat(property, is(notNullValue()));
assertThat(property.getType(), is(typeCompatibleWith(String.class)));
property = from.getProperty("name");
assertThat(property, is(notNullValue()));
assertThat(property.getType(), is(typeCompatibleWith(byte[].class)));
}
static class StringMapContainer extends MapContainer<String> {
}
@ -199,4 +213,12 @@ public class ClassTypeInformationUnitTests { @@ -199,4 +213,12 @@ public class ClassTypeInformationUnitTests {
static class AnotherConcreteWrapper extends GenericWrapper<Long> {
}
static class PropertyGetter {
private String _name;
public byte[] getName() {
return _name.getBytes();
}
}
}

Loading…
Cancel
Save