Browse Source

DATACMNS-85 - Extended PersistenPropertyPath.

PersistentPropertyPath got a few new methods to build String representations of it. Beyond that we introduced accessor methods for the base and leaf path as well as the ability to detect base paths and create path extensions based on a given base path.
pull/12/head
Oliver Gierke 15 years ago
parent
commit
a73e2ed3e0
  1. 2
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyPath.java
  2. 140
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java
  3. 63
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPath.java
  4. 47
      spring-data-commons-core/src/test/java/org/springframework/data/mapping/context/DefaultPersistenPropertyPathUnitTest.java

2
spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyPath.java

@ -149,7 +149,7 @@ public class PropertyPath implements Iterable<PropertyPath> { @@ -149,7 +149,7 @@ public class PropertyPath implements Iterable<PropertyPath> {
}
/**
* Returns the {@link PropertyPath} path in dot notation.
* Returns the {@link PropertyPath} in dot notation.
*
* @return
*/

140
spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java

@ -26,50 +26,144 @@ import org.springframework.util.StringUtils; @@ -26,50 +26,144 @@ import org.springframework.util.StringUtils;
/**
* Abstraction of a path of {@link PersistentProperty}s.
*
*
* @author Oliver Gierke
*/
class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements PersistentPropertyPath<T> {
private final Iterable<T> properties;
private enum PropertyNameConverter implements Converter<PersistentProperty<?>, String> {
INSTANCE;
public String convert(PersistentProperty<?> source) {
return source.getName();
}
}
private final List<T> properties;
/**
* Creates a new {@link DefaultPersistentPropertyPath} for the given {@link PersistentProperty}s.
*
* @param properties must not be {@literal null}.
*/
public DefaultPersistentPropertyPath(Iterable<T> properties) {
public DefaultPersistentPropertyPath(List<T> properties) {
Assert.notNull(properties);
Assert.isTrue(!properties.isEmpty());
this.properties = properties;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath()
*/
public String toDotPath() {
return toDotPath(new Converter<T, String>() {
public String convert(T source) {
return source.getName();
}
});
return toPath(null, null);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath(org.springframework.core.convert.converter.Converter)
*/
public String toDotPath(Converter<? super T, String> converter) {
return toPath(null, converter);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String)
*/
public String toPath(String delimiter) {
return toPath(delimiter, null);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String, org.springframework.core.convert.converter.Converter)
*/
public String toPath(String delimiter, Converter<? super T, String> converter) {
@SuppressWarnings("unchecked")
Converter<? super T, String> converterToUse = (Converter<? super T, String>) (converter == null ? PropertyNameConverter.INSTANCE
: converter);
String delimiterToUse = delimiter == null ? "." : delimiter;
List<String> result = new ArrayList<String>();
for (T property : properties) {
result.add(converter.convert(property));
result.add(converterToUse.convert(property));
}
return StringUtils.collectionToDelimitedString(result, ".");
return StringUtils.collectionToDelimitedString(result, delimiterToUse);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getLeafProperty()
*/
public T getLeafProperty() {
return properties.get(properties.size() - 1);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getBaseProperty()
*/
public T getBaseProperty() {
return properties.get(0);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#isBasePathOf(org.springframework.data.mapping.context.PersistentPropertyPath)
*/
public boolean isBasePathOf(PersistentPropertyPath<T> path) {
if (path == null) {
return false;
}
Iterator<T> iterator = path.iterator();
for (T property : this) {
if (!iterator.hasNext()) {
return false;
}
T reference = iterator.next();
if (!property.equals(reference)) {
return false;
}
}
return true;
}
/* (non-Javadoc)
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getExtensionForBaseOf(org.springframework.data.mapping.context.PersistentPropertyPath)
*/
public PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base) {
if (!base.isBasePathOf(this)) {
return this;
}
List<T> properties = new ArrayList<T>();
Iterator<T> iterator = iterator();
for (@SuppressWarnings("unused") T candidate : base) {
iterator.next();
}
while (iterator.hasNext()) {
properties.add(iterator.next());
}
return new DefaultPersistentPropertyPath<T>(properties);
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
@ -77,27 +171,27 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements @@ -77,27 +171,27 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
public Iterator<T> 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()

63
spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPath.java

@ -15,20 +15,18 @@ @@ -15,20 +15,18 @@
*/
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<T extends PersistentProperty<T>> extends Iterable<T> {
/**
* Returns the dot based path notation using the {@link PersistentProperty}'s name attribute.
* Returns the dot based path notation using {@link PersistentProperty#getName()}.
*
* @return
*/
@ -43,9 +41,58 @@ public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends @@ -43,9 +41,58 @@ public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends
*/
String toDotPath(Converter<? super T, String> converter);
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
/**
* Returns a {@link String} path with the given delimiter based on the {@link PersistentProperty#getName()}.
*
* @param delimiter will default to {@code .} if {@literal null} is given.
* @return
*/
String toPath(String delimiter);
/**
* Returns a {@link String} path with the given delimiter using the given {@link Converter} for
* {@link PersistentProperty} to String conversion.
*
* @param delimiter will default to {@code .} if {@literal null} is given.
* @param converter will default to use {@link PersistentProperty#getName()}.
* @return
*/
String toPath(String delimiter, Converter<? super T, String> converter);
/**
* Returns the last property in the {@link PersistentPropertyPath}. So for {@code foo.bar} it will return the
* {@link PersistentProperty} for {@code bar}. For a simple {@code foo} it returns {@link PersistentProperty} for
* {@code foo}.
*
* @return
*/
T getLeafProperty();
/**
* Returns the first property in the {@link PersistentPropertyPath}. So for {@code foo.bar} it will return the
* {@link PersistentProperty} for {@code foo}. For a simple {@code foo} it returns {@link PersistentProperty} for
* {@code foo}.
*
* @return
*/
T getBaseProperty();
/**
* Returns whether the given {@link PersistentPropertyPath} is a base path of the current one. This means that the
* current {@link PersistentPropertyPath} is basically an extension of the given one.
*
* @param path
* @return
*/
boolean isBasePathOf(PersistentPropertyPath<T> path);
/**
* Returns the sub-path of the current one as if it was based on the given base path. So for a current path
* {@code foo.bar} and a given base {@code foo} it would return {@code bar}. If the given path is not a base of the
* the current one the current {@link PersistentPropertyPath} will be returned as is.
*
* @param base
* @return
*/
Iterator<T> iterator();
PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base);
}

47
spring-data-commons-core/src/test/java/org/springframework/data/mapping/context/DefaultPersistenPropertyPathUnitTest.java

@ -22,6 +22,7 @@ import static org.mockito.Mockito.*; @@ -22,6 +22,7 @@ import static org.mockito.Mockito.*;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@ -43,6 +44,16 @@ public class DefaultPersistenPropertyPathUnitTest<T extends PersistentProperty<T @@ -43,6 +44,16 @@ public class DefaultPersistenPropertyPathUnitTest<T extends PersistentProperty<T
@Mock
Converter<T, String> converter;
PersistentPropertyPath<T> oneLeg;
PersistentPropertyPath<T> twoLegs;
@Before
@SuppressWarnings("unchecked")
public void setUp() {
oneLeg = new DefaultPersistentPropertyPath<T>(Arrays.asList(first));
twoLegs = new DefaultPersistentPropertyPath<T>(Arrays.asList(first, second));
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullProperties() {
@ -50,14 +61,12 @@ public class DefaultPersistenPropertyPathUnitTest<T extends PersistentProperty<T @@ -50,14 +61,12 @@ public class DefaultPersistenPropertyPathUnitTest<T extends PersistentProperty<T
}
@Test
@SuppressWarnings("unchecked")
public void usesPropertyNameForSimpleDotPath() {
when(first.getName()).thenReturn("foo");
when(second.getName()).thenReturn("bar");
PersistentPropertyPath<T> path = new DefaultPersistentPropertyPath<T>(Arrays.asList(first, second));
assertThat(path.toDotPath(), is("foo.bar"));
assertThat(twoLegs.toDotPath(), is("foo.bar"));
}
@Test
@ -66,7 +75,35 @@ public class DefaultPersistenPropertyPathUnitTest<T extends PersistentProperty<T @@ -66,7 +75,35 @@ public class DefaultPersistenPropertyPathUnitTest<T extends PersistentProperty<T
when(converter.convert((T) any())).thenReturn("foo");
PersistentPropertyPath<T> path = new DefaultPersistentPropertyPath<T>(Arrays.asList(first, second));
assertThat(path.toDotPath(converter), is("foo.foo"));
assertThat(twoLegs.toDotPath(converter), is("foo.foo"));
}
@Test
public void returnsCorrectLeafProperty() {
assertThat(twoLegs.getLeafProperty(), is(second));
assertThat(oneLeg.getLeafProperty(), is(first));
}
@Test
public void returnsCorrectBaseProperty() {
assertThat(twoLegs.getBaseProperty(), is(first));
assertThat(oneLeg.getBaseProperty(), is(first));
}
@Test
public void detectsBasePathCorrectly() {
assertThat(oneLeg.isBasePathOf(twoLegs), is(true));
assertThat(twoLegs.isBasePathOf(oneLeg), is(false));
}
@Test
@SuppressWarnings("unchecked")
public void calculatesExtensionCorrectly() {
PersistentPropertyPath<T> extension = twoLegs.getExtensionForBaseOf(oneLeg);
assertThat(extension, is((PersistentPropertyPath<T>) new DefaultPersistentPropertyPath<T>(Arrays.asList(second))));
}
}

Loading…
Cancel
Save