diff --git a/Spring Data Commons.sonargraph b/Spring Data Commons.sonargraph index c207aebce..880ebc07c 100644 --- a/Spring Data Commons.sonargraph +++ b/Spring Data Commons.sonargraph @@ -65,6 +65,7 @@ + diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/domain/Sort.java b/spring-data-commons-core/src/main/java/org/springframework/data/domain/Sort.java index f41e07b35..ec54bb2bd 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/domain/Sort.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/domain/Sort.java @@ -217,7 +217,7 @@ public class Sort implements Iterable { private static final String DELIMITERS = "_\\."; private static final Pattern SPLITTER = Pattern.compile("(?:[%s]?([%s]*?[^%s]+))".replaceAll("%s", DELIMITERS)); @@ -42,26 +42,26 @@ public class Property { private final TypeInformation type; private final boolean isCollection; - private Property next; + private PropertyPath next; /** - * Creates a leaf {@link Property} (no nested ones) with the given name inside the given owning type. + * Creates a leaf {@link PropertyPath} (no nested ones) with the given name inside the given owning type. * * @param name * @param owningType */ - Property(String name, Class owningType) { + PropertyPath(String name, Class owningType) { this(name, ClassTypeInformation.from(owningType)); } /** - * Creates a leaf {@link Property} (no nested ones with the given name and owning type. + * Creates a leaf {@link PropertyPath} (no nested ones with the given name and owning type. * * @param name * @param owningType */ - Property(String name, TypeInformation owningType) { + PropertyPath(String name, TypeInformation owningType) { Assert.hasText(name); Assert.notNull(owningType); @@ -80,14 +80,14 @@ public class Property { } /** - * Creates a {@link Property} with the given name inside the given owning type and tries to resolve the other + * Creates a {@link PropertyPath} with the given name inside the given owning type and tries to resolve the other * {@link String} to create nested properties. * * @param name * @param owningType * @param toTraverse */ - Property(String name, TypeInformation owningType, String toTraverse) { + PropertyPath(String name, TypeInformation owningType, String toTraverse) { this(name, owningType); @@ -97,7 +97,7 @@ public class Property { } /** - * Returns the owning type of the {@link Property}. + * Returns the owning type of the {@link PropertyPath}. * * @return the owningType will never be {@literal null}. */ @@ -106,11 +106,11 @@ public class Property { } /** - * Returns the name of the {@link Property}. + * Returns the name of the {@link PropertyPath}. * * @return the name will never be {@literal null}. */ - public String getName() { + public String getSegment() { return name; } @@ -127,18 +127,18 @@ public class Property { } /** - * Returns the next nested {@link Property}. + * Returns the next nested {@link PropertyPath}. * - * @return the next nested {@link Property} or {@literal null} if no nested {@link Property} available. + * @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available. * @see #hasNext() */ - public Property next() { + public PropertyPath next() { return next; } /** - * Returns whether there is a nested {@link Property}. If this returns {@literal true} you can expect {@link #next()} + * Returns whether there is a nested {@link PropertyPath}. If this returns {@literal true} you can expect {@link #next()} * to return a non- {@literal null} value. * * @return @@ -149,21 +149,21 @@ public class Property { } /** - * Returns the {@link Property} path in dot notation. + * Returns the {@link PropertyPath} path in dot notation. * * @return */ public String toDotPath() { if (hasNext()) { - return getName() + "." + next().toDotPath(); + return getSegment() + "." + next().toDotPath(); } - return getName(); + return getSegment(); } /** - * Returns whether the {@link Property} is actually a collection. + * Returns whether the {@link PropertyPath} is actually a collection. * * @return */ @@ -173,10 +173,9 @@ public class Property { } /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ @Override public boolean equals(Object obj) { @@ -188,35 +187,59 @@ public class Property { return false; } - Property that = (Property) obj; + PropertyPath that = (PropertyPath) obj; return this.name.equals(that.name) && this.type.equals(that.type); } /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ @Override public int hashCode() { return name.hashCode() + type.hashCode(); } + /* + * (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + public Iterator iterator() { + return new Iterator() { + + private PropertyPath current = PropertyPath.this; + + public boolean hasNext() { + return current != null; + } + + public PropertyPath next() { + PropertyPath result = current; + this.current = current.next(); + return result; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + /** - * Extracts the {@link Property} chain from the given source {@link String} and type. + * Extracts the {@link PropertyPath} chain from the given source {@link String} and type. * * @param source * @param type * @return */ - public static Property from(String source, Class type) { + public static PropertyPath from(String source, Class type) { return from(source, ClassTypeInformation.from(type)); } - private static Property from(String source, TypeInformation type) { + private static PropertyPath from(String source, TypeInformation type) { List iteratorSource = new ArrayList(); Matcher matcher = SPLITTER.matcher("_" + source); @@ -227,8 +250,8 @@ public class Property { Iterator parts = iteratorSource.iterator(); - Property result = null; - Property current = null; + PropertyPath result = null; + PropertyPath current = null; while (parts.hasNext()) { if (result == null) { @@ -243,21 +266,21 @@ public class Property { } /** - * Creates a new {@link Property} as subordinary of the given {@link Property}. + * Creates a new {@link PropertyPath} as subordinary of the given {@link PropertyPath}. * * @param source * @param base * @return */ - private static Property create(String source, Property base) { + private static PropertyPath create(String source, PropertyPath base) { - Property property = create(source, base.type); - base.next = property; - return property; + PropertyPath propertyPath = create(source, base.type); + base.next = propertyPath; + return propertyPath; } /** - * Factory method to create a new {@link Property} for the given {@link String} and owning type. It will inspect the + * Factory method to create a new {@link PropertyPath} for the given {@link String} and owning type. It will inspect the * given source for camel-case parts and traverse the {@link String} along its parts starting with the entire one and * chewing off parts from the right side then. Whenever a valid property for the given class is found, the tail will * be traversed for subordinary properties of the just found one and so on. @@ -266,14 +289,14 @@ public class Property { * @param type * @return */ - private static Property create(String source, TypeInformation type) { + private static PropertyPath create(String source, TypeInformation type) { return create(source, type, ""); } /** - * Tries to look up a chain of {@link Property}s by trying the givne source first. If that fails it will split the - * source apart at camel case borders (starting from the right side) and try to look up a {@link Property} from the + * Tries to look up a chain of {@link PropertyPath}s by trying the givne source first. If that fails it will split the + * source apart at camel case borders (starting from the right side) and try to look up a {@link PropertyPath} from the * calculated head and recombined new tail and additional tail. * * @param source @@ -281,12 +304,12 @@ public class Property { * @param addTail * @return */ - private static Property create(String source, TypeInformation type, String addTail) { + private static PropertyPath create(String source, TypeInformation type, String addTail) { IllegalArgumentException exception = null; try { - return new Property(source, type, addTail); + return new PropertyPath(source, type, addTail); } catch (IllegalArgumentException e) { exception = e; } diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java index d9cf0538c..5fe42c595 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java @@ -40,6 +40,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.event.MappingContextEvent; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.MutablePersistentEntity; @@ -169,25 +170,24 @@ public abstract class AbstractMappingContext Iterable

getPersistentPropertyPath(Class type, String path) { + public PersistentPropertyPath

getPersistentPropertyPath(PropertyPath propertyPath) { - Iterator parts = Arrays.asList(path.split("\\.")).iterator(); List

result = new ArrayList

(); - E current = getPersistentEntity(type); + E current = getPersistentEntity(propertyPath.getOwningType()); + + for (PropertyPath segment : propertyPath) { + + P persistentProperty = current.getPersistentProperty(segment.getSegment()); - while (parts.hasNext()) { - String name = parts.next(); - P property = current.getPersistentProperty(name); - - if (property == null) { - throw new IllegalArgumentException(String.format("No property %s found on %s!", name, current.getName())); + if (persistentProperty == null) { + throw new IllegalArgumentException(String.format("No property %s found on %s!", segment.getSegment(), current.getName())); } - - result.add(property); - current = getPersistentEntity(property.getTypeInformation().getActualType()); + + result.add(persistentProperty); + current = getPersistentEntity(segment.getType()); } - - return result; + + return new DefaultPersistentPropertyPath

(result); } /* @@ -334,7 +334,7 @@ public abstract class AbstractMappingContext> implements PersistentPropertyPath { + + private final Iterable properties; + + /** + * Creates a new {@link DefaultPersistentPropertyPath} for the given {@link PersistentProperty}s. + * + * @param properties must not be {@literal null}. + */ + public DefaultPersistentPropertyPath(Iterable properties) { + Assert.notNull(properties); + this.properties = properties; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath() + */ + public String toDotPath() { + return toDotPath(new Converter() { + public String convert(T source) { + return source.getName(); + } + }); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath(org.springframework.core.convert.converter.Converter) + */ + public String toDotPath(Converter converter) { + + List result = new ArrayList(); + + for (T property : properties) { + result.add(converter.convert(property)); + } + + return StringUtils.collectionToDelimitedString(result, "."); + } + + /* + * (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + public Iterator iterator() { + return properties.iterator(); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj == null || !getClass().equals(obj.getClass())) { + return false; + } + + DefaultPersistentPropertyPath that = (DefaultPersistentPropertyPath) obj; + + return this.properties.equals(that.properties); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return properties.hashCode(); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContext.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContext.java index 663882294..889e7c689 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContext.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContext.java @@ -17,6 +17,7 @@ package org.springframework.data.mapping.context; import java.util.Collection; import java.util.List; +import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.util.TypeInformation; @@ -69,15 +70,14 @@ public interface MappingContext, P extends Pers E getPersistentEntity(TypeInformation type); /** - * Returns all {@link PersistentProperty}s for the given path expression based on the given root {@link Class}. Path - * expression are dot separated, e.g. {@code person.firstname}. + * Returns all {@link PersistentProperty}s for the given path expression based on the given {@link PropertyPath}. * * @param * @param type * @param path * @return */ - Iterable

getPersistentPropertyPath(Class type, String path); + PersistentPropertyPath

getPersistentPropertyPath(PropertyPath propertyPath); /** * Obtains a validator for the given entity TODO: Why do we need validators at the {@link MappingContext}? diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPath.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPath.java new file mode 100644 index 000000000..aca089213 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPath.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.context; + +import java.util.Iterator; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.mapping.PersistentProperty; + +/** + * Abstraction of a path of {@link PersistentProperty}s. + * + * @author Oliver Gierke + */ +public interface PersistentPropertyPath> extends Iterable { + + /** + * Returns the dot based path notation using the {@link PersistentProperty}'s name attribute. + * + * @return + */ + String toDotPath(); + + /** + * Returns the dot based path notation using the given {@link Converter} to translate individual + * {@link PersistentProperty}s to path segments. + * + * @param converter + * @return + */ + String toDotPath(Converter converter); + + /* + * (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + Iterator iterator(); +} \ No newline at end of file diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/OrderBySource.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/OrderBySource.java index 8a67af1c3..ad66c533d 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/OrderBySource.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/OrderBySource.java @@ -23,6 +23,7 @@ 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.data.mapping.PropertyPath; import org.springframework.util.StringUtils; /** @@ -78,15 +79,15 @@ public class OrderBySource { * @param direction * @param domainClass can be {@literal null}. * @return - * @see Property#from(String, Class) + * @see PropertyPath#from(String, Class) */ private Order createOrder(String propertySource, Direction direction, Class domainClass) { if (null == domainClass) { return new Order(direction, StringUtils.uncapitalize(propertySource)); } - Property property = Property.from(propertySource, domainClass); - return new Order(direction, property.toDotPath()); + PropertyPath propertyPath = PropertyPath.from(propertySource, domainClass); + return new Order(direction, propertyPath.toDotPath()); } /** diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java index 27e12f5ff..711bfc954 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.springframework.data.mapping.PropertyPath; import org.springframework.util.StringUtils; /** @@ -33,7 +34,7 @@ public class Part { private static final Pattern IGNORE_CASE = Pattern.compile("Ignor(ing|e)Case"); - private final Property property; + private final PropertyPath propertyPath; private final Part.Type type; private IgnoreCaseType ignoreCase = IgnoreCaseType.NEVER; @@ -65,7 +66,7 @@ public class Part { this.ignoreCase = IgnoreCaseType.WHEN_POSSIBLE; } this.type = Type.fromProperty(partToUse); - this.property = Property.from(type.extractProperty(partToUse), clazz); + this.propertyPath = PropertyPath.from(type.extractProperty(partToUse), clazz); } private String detectAndSetIgnoreCase(String part) { @@ -97,11 +98,11 @@ public class Part { } /** - * @return the property + * @return the propertyPath */ - public Property getProperty() { + public PropertyPath getProperty() { - return property; + return propertyPath; } /** @@ -113,7 +114,7 @@ public class Part { } /** - * Returns whether the {@link Property} referenced should be matched ignoring case. + * Returns whether the {@link PropertyPath} referenced should be matched ignoring case. * * @return */ @@ -138,7 +139,7 @@ public class Part { } Part that = (Part) obj; - return this.property.equals(that.property) && this.type.equals(that.type); + return this.propertyPath.equals(that.propertyPath) && this.type.equals(that.type); } /* @@ -149,7 +150,7 @@ public class Part { public int hashCode() { int result = 37; - result += 17 * property.hashCode(); + result += 17 * propertyPath.hashCode(); result += 17 * type.hashCode(); return result; } @@ -161,7 +162,7 @@ public class Part { @Override public String toString() { - return String.format("%s %s", property.getName(), type); + return String.format("%s %s", propertyPath.getSegment(), type); } /** @@ -228,8 +229,8 @@ public class Part { } /** - * Returns the {@link Type} of the {@link Part} for the given raw property. This will - * try to detect e.g. keywords contained in the raw property that trigger special query creation. Returns + * Returns the {@link Type} of the {@link Part} for the given raw propertyPath. This will + * try to detect e.g. keywords contained in the raw propertyPath that trigger special query creation. Returns * {@link #SIMPLE_PROPERTY} by default. * * @param rawProperty @@ -247,10 +248,10 @@ public class Part { } /** - * Returns whether the the type supports the given raw property. Default implementation checks whether the property - * ends with the registered keyword. Does not support the keyword if the property is a valid field as is. + * Returns whether the the type supports the given raw propertyPath. Default implementation checks whether the propertyPath + * ends with the registered keyword. Does not support the keyword if the propertyPath is a valid field as is. * - * @param property + * @param propertyPath * @return */ protected boolean supports(String property) { @@ -269,7 +270,7 @@ public class Part { } /** - * Returns the number of arguments the property binds. By default this exactly one argument. + * Returns the number of arguments the propertyPath binds. By default this exactly one argument. * * @return */ @@ -279,7 +280,7 @@ public class Part { } /** - * Callback method to extract the actual property to be bound from the given part. Strips the keyword from the + * Callback method to extract the actual propertyPath to be bound from the given part. Strips the keyword from the * part's end if available. * * @param part diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java index f193e2179..018045958 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java @@ -59,7 +59,7 @@ public class PartTree implements Iterable { public PartTree(String source, Class domainClass) { Assert.notNull(source, "Source must not be null"); - Assert.notNull(domainClass, "DomainClass must not be null"); + Assert.notNull(domainClass, "Domain class must not be null"); Matcher matcher = PREFIX_TEMPLATE.matcher(source); if (!matcher.find()) { @@ -99,7 +99,7 @@ public class PartTree implements Iterable { return subject.isDistinct(); } - + /** * Returns an {@link Iterable} of all parts contained in the {@link PartTree}. * diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/util/ClassTypeInformation.java b/spring-data-commons-core/src/main/java/org/springframework/data/util/ClassTypeInformation.java index ee3a6dc76..1e1755a03 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/util/ClassTypeInformation.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/util/ClassTypeInformation.java @@ -23,7 +23,7 @@ import java.util.Map; import org.springframework.util.Assert; /** - * Property information for a plain {@link Class}. + * PropertyPath information for a plain {@link Class}. * * @author Oliver Gierke */ diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PropertyUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PropertyUnitTests.java similarity index 51% rename from spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PropertyUnitTests.java rename to spring-data-commons-core/src/test/java/org/springframework/data/mapping/PropertyUnitTests.java index f57ba2ebc..1c0273475 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PropertyUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PropertyUnitTests.java @@ -13,20 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.repository.query.parser; +package org.springframework.data.mapping; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Test; - +import org.springframework.data.mapping.PropertyPath; /** - * Unit tests for {@link Property}. - * + * Unit tests for {@link PropertyPath}. + * * @author Oliver Gierke */ @SuppressWarnings("unused") @@ -35,99 +38,92 @@ public class PropertyUnitTests { @Test public void parsesSimplePropertyCorrectly() throws Exception { - Property reference = Property.from("userName", Foo.class); + PropertyPath reference = PropertyPath.from("userName", Foo.class); assertThat(reference.hasNext(), is(false)); assertThat(reference.toDotPath(), is("userName")); } - @Test public void parsesPathPropertyCorrectly() throws Exception { - Property reference = Property.from("userName", Bar.class); + PropertyPath reference = PropertyPath.from("userName", Bar.class); assertThat(reference.hasNext(), is(true)); - assertThat(reference.next(), is(new Property("name", FooBar.class))); + assertThat(reference.next(), is(new PropertyPath("name", FooBar.class))); assertThat(reference.toDotPath(), is("user.name")); } - @Test public void prefersLongerMatches() throws Exception { - Property reference = Property.from("userName", Sample.class); + PropertyPath reference = PropertyPath.from("userName", Sample.class); assertThat(reference.hasNext(), is(false)); assertThat(reference.toDotPath(), is("userName")); } - @Test public void testname() throws Exception { - Property reference = Property.from("userName", Sample2.class); - assertThat(reference.getName(), is("user")); + PropertyPath reference = PropertyPath.from("userName", Sample2.class); + assertThat(reference.getSegment(), is("user")); assertThat(reference.hasNext(), is(true)); - assertThat(reference.next(), is(new Property("name", FooBar.class))); + assertThat(reference.next(), is(new PropertyPath("name", FooBar.class))); } - @Test public void prefersExplicitPaths() throws Exception { - Property reference = Property.from("user_name", Sample.class); - assertThat(reference.getName(), is("user")); + PropertyPath reference = PropertyPath.from("user_name", Sample.class); + assertThat(reference.getSegment(), is("user")); assertThat(reference.hasNext(), is(true)); - assertThat(reference.next(), is(new Property("name", FooBar.class))); + assertThat(reference.next(), is(new PropertyPath("name", FooBar.class))); } - @Test public void handlesGenericsCorrectly() throws Exception { - Property reference = Property.from("usersName", Bar.class); - assertThat(reference.getName(), is("users")); + PropertyPath reference = PropertyPath.from("usersName", Bar.class); + assertThat(reference.getSegment(), is("users")); assertThat(reference.isCollection(), is(true)); assertThat(reference.hasNext(), is(true)); - assertThat(reference.next(), is(new Property("name", FooBar.class))); + assertThat(reference.next(), is(new PropertyPath("name", FooBar.class))); } - @Test public void handlesMapCorrectly() throws Exception { - Property reference = Property.from("userMapName", Bar.class); - assertThat(reference.getName(), is("userMap")); + PropertyPath reference = PropertyPath.from("userMapName", Bar.class); + assertThat(reference.getSegment(), is("userMap")); assertThat(reference.isCollection(), is(false)); assertThat(reference.hasNext(), is(true)); - assertThat(reference.next(), is(new Property("name", FooBar.class))); + assertThat(reference.next(), is(new PropertyPath("name", FooBar.class))); } - @Test public void handlesArrayCorrectly() throws Exception { - Property reference = Property.from("userArrayName", Bar.class); - assertThat(reference.getName(), is("userArray")); + PropertyPath reference = PropertyPath.from("userArrayName", Bar.class); + assertThat(reference.getSegment(), is("userArray")); assertThat(reference.isCollection(), is(true)); assertThat(reference.hasNext(), is(true)); - assertThat(reference.next(), is(new Property("name", FooBar.class))); + assertThat(reference.next(), is(new PropertyPath("name", FooBar.class))); } @Test(expected = IllegalArgumentException.class) public void handlesInvalidCollectionCompountTypeProperl() { - Property.from("usersMame", Bar.class); + PropertyPath.from("usersMame", Bar.class); } @Test(expected = IllegalArgumentException.class) public void handlesInvalidMapValueTypeProperl() { - Property.from("userMapMame", Bar.class); + PropertyPath.from("userMapMame", Bar.class); } @Test public void findsNested() { - Property from = Property.from("barUserName", Sample.class); + PropertyPath from = PropertyPath.from("barUserName", Sample.class); } /** @@ -135,20 +131,44 @@ public class PropertyUnitTests { */ @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")); + + PropertyPath propertyPath = PropertyPath.from("_foo", Sample2.class); + assertThat(propertyPath.getSegment(), is("_foo")); + assertThat(propertyPath.getType(), is(typeCompatibleWith(Foo.class))); + + propertyPath = PropertyPath.from("_foo__email", Sample2.class); + assertThat(propertyPath.toDotPath(), is("_foo._email")); } - + @Test public void supportsDotNotationAsWell() { - Property.from("bar.userMap.name", Sample.class); + PropertyPath.from("bar.userMap.name", Sample.class); } - + + @Test + public void returnsCorrectIteratorForSingleElement() { + + PropertyPath propertyPath = PropertyPath.from("userName", Foo.class); + + Iterator iterator = propertyPath.iterator(); + assertThat(iterator.hasNext(), is(true)); + assertThat(iterator.next(), is(propertyPath)); + assertThat(iterator.hasNext(), is(false)); + } + + @Test + public void returnsCorrectIteratorForMultipleElement() { + + PropertyPath propertyPath = PropertyPath.from("user.name", Bar.class); + + Iterator iterator = propertyPath.iterator(); + assertThat(iterator.hasNext(), is(true)); + assertThat(iterator.next(), is(propertyPath)); + assertThat(iterator.hasNext(), is(true)); + assertThat(iterator.next(), is(propertyPath.next())); + assertThat(iterator.hasNext(), is(false)); + } + private class Foo { String userName; diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/context/DefaultPersistenPropertyPathUnitTest.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/context/DefaultPersistenPropertyPathUnitTest.java new file mode 100644 index 000000000..2279229c9 --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/context/DefaultPersistenPropertyPathUnitTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.context; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.util.Arrays; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.mapping.context.PersistentPropertyPath; + +/** + * Unit tests for {@link DefaultPersistentPropertyPath}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class DefaultPersistenPropertyPathUnitTest> { + + @Mock + T first, second; + + @Mock + Converter converter; + + @Test(expected = IllegalArgumentException.class) + public void rejectsNullProperties() { + new DefaultPersistentPropertyPath(null); + } + + @Test + @SuppressWarnings("unchecked") + public void usesPropertyNameForSimpleDotPath() { + + when(first.getName()).thenReturn("foo"); + when(second.getName()).thenReturn("bar"); + + PersistentPropertyPath path = new DefaultPersistentPropertyPath(Arrays.asList(first, second)); + assertThat(path.toDotPath(), is("foo.bar")); + } + + @Test + @SuppressWarnings("unchecked") + public void usesConverterToCreatePropertyPath() { + + when(converter.convert((T) any())).thenReturn("foo"); + + PersistentPropertyPath path = new DefaultPersistentPropertyPath(Arrays.asList(first, second)); + assertThat(path.toDotPath(converter), is("foo.foo")); + } +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java index 194859a85..2e50e5c9b 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java @@ -25,6 +25,7 @@ import java.util.Iterator; import org.junit.Test; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.mapping.PropertyPath; import org.springframework.data.repository.query.parser.Part.IgnoreCaseType; import org.springframework.data.repository.query.parser.Part.Type; import org.springframework.data.repository.query.parser.PartTree.OrPart; @@ -226,8 +227,8 @@ public class PartTreeUnitTests { return parts; } - private Property newProperty(String name) { - return new Property(name, User.class); + private PropertyPath newProperty(String name) { + return PropertyPath.from(name, User.class); } private void assertPart(PartTree tree, Part[]... parts) {