Skip to content

Commit c916fcb

Browse files
committed
DATACMNS-801 - Make sure PropertyReferenceException does not expose duplicate potential matches.
We now use a Set to collect potential matches from fields and accessors. Polished assertions and JavaDoc in PropertyPath along the way.
1 parent 80e44a3 commit c916fcb

File tree

3 files changed

+125
-15
lines changed

3 files changed

+125
-15
lines changed

src/main/java/org/springframework/data/mapping/PropertyPath.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.data.mapping;
1717

1818
import java.util.ArrayList;
19+
import java.util.Collections;
1920
import java.util.Iterator;
2021
import java.util.List;
2122
import java.util.Stack;
@@ -53,7 +54,7 @@ public class PropertyPath implements Iterable<PropertyPath> {
5354
* @param owningType must not be {@literal null}.
5455
*/
5556
PropertyPath(String name, Class<?> owningType) {
56-
this(name, ClassTypeInformation.from(owningType), null);
57+
this(name, ClassTypeInformation.from(owningType), Collections.<PropertyPath> emptyList());
5758
}
5859

5960
/**
@@ -65,8 +66,9 @@ public class PropertyPath implements Iterable<PropertyPath> {
6566
*/
6667
PropertyPath(String name, TypeInformation<?> owningType, List<PropertyPath> base) {
6768

68-
Assert.hasText(name);
69-
Assert.notNull(owningType);
69+
Assert.hasText(name, "Name must not be null or empty!");
70+
Assert.notNull(owningType, "Owning type must not be null!");
71+
Assert.notNull(base, "Perviously found properties must not be null!");
7072

7173
String propertyName = name.matches(ALL_UPPERCASE) ? name : StringUtils.uncapitalize(name);
7274
TypeInformation<?> propertyType = owningType.getProperty(propertyName);

src/main/java/org/springframework/data/mapping/PropertyReferenceException.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2015 the original author or authors.
2+
* Copyright 2012-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,9 +15,11 @@
1515
*/
1616
package org.springframework.data.mapping;
1717

18-
import java.util.ArrayList;
1918
import java.util.Arrays;
19+
import java.util.Collection;
20+
import java.util.HashSet;
2021
import java.util.List;
22+
import java.util.Set;
2123

2224
import org.springframework.beans.PropertyMatches;
2325
import org.springframework.data.util.TypeInformation;
@@ -38,20 +40,21 @@ public class PropertyReferenceException extends RuntimeException {
3840
private final String propertyName;
3941
private final TypeInformation<?> type;
4042
private final List<PropertyPath> alreadyResolvedPath;
41-
private final List<String> propertyMatches;
43+
private final Set<String> propertyMatches;
4244

4345
/**
4446
* Creates a new {@link PropertyReferenceException}.
4547
*
46-
* @param propertyName the name of the property not found on the given type.
47-
* @param type the type the property could not be found on.
48-
* @param alreadyResolvedPah the previously calculated {@link PropertyPath}s.
48+
* @param propertyName the name of the property not found on the given type, must not be {@literal null} or empty.
49+
* @param type the type the property could not be found on, must not be {@literal null}.
50+
* @param alreadyResolvedPah the previously calculated {@link PropertyPath}s, must not be {@literal null}.
4951
*/
5052
public PropertyReferenceException(String propertyName, TypeInformation<?> type,
5153
List<PropertyPath> alreadyResolvedPah) {
5254

53-
Assert.hasText(propertyName);
54-
Assert.notNull(type);
55+
Assert.hasText(propertyName, "Property name must not be null!");
56+
Assert.notNull(type, "Type must not be null!");
57+
Assert.notNull(alreadyResolvedPah, "Already resolved paths must not be null!");
5558

5659
this.propertyName = propertyName;
5760
this.type = type;
@@ -71,12 +74,21 @@ public String getPropertyName() {
7174
/**
7275
* Returns the type the property could not be found on.
7376
*
74-
* @return the type
77+
* @return will never be {@literal null}.
7578
*/
7679
public TypeInformation<?> getType() {
7780
return type;
7881
}
7982

83+
/**
84+
* Returns the properties that the invalid property might have been meant to be referred to.
85+
*
86+
* @return will never be {@literal null}.
87+
*/
88+
Collection<String> getPropertyMatches() {
89+
return propertyMatches;
90+
}
91+
8092
/*
8193
* (non-Javadoc)
8294
* @see java.lang.Throwable#getMessage()
@@ -114,7 +126,7 @@ public PropertyPath getBaseProperty() {
114126
* Returns whether the given {@link PropertyReferenceException} has a deeper resolution depth (i.e. a longer path of
115127
* already resolved properties) than the current exception.
116128
*
117-
* @param exception
129+
* @param exception must not be {@literal null}.
118130
* @return
119131
*/
120132
public boolean hasDeeperResolutionDepthThan(PropertyReferenceException exception) {
@@ -128,9 +140,9 @@ public boolean hasDeeperResolutionDepthThan(PropertyReferenceException exception
128140
* @param type must not be {@literal null}.
129141
* @return
130142
*/
131-
private static List<String> detectPotentialMatches(String propertyName, Class<?> type) {
143+
private static Set<String> detectPotentialMatches(String propertyName, Class<?> type) {
132144

133-
List<String> result = new ArrayList<String>();
145+
Set<String> result = new HashSet<String>();
134146
result.addAll(Arrays.asList(PropertyMatches.forField(propertyName, type).getPossibleMatches()));
135147
result.addAll(Arrays.asList(PropertyMatches.forProperty(propertyName, type).getPossibleMatches()));
136148

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mapping;
17+
18+
import static org.hamcrest.Matchers.*;
19+
import static org.junit.Assert.*;
20+
21+
import java.util.Collection;
22+
import java.util.Collections;
23+
import java.util.List;
24+
25+
import org.junit.Rule;
26+
import org.junit.Test;
27+
import org.junit.rules.ExpectedException;
28+
import org.springframework.data.util.ClassTypeInformation;
29+
import org.springframework.data.util.TypeInformation;
30+
31+
/**
32+
* Unit tests for {@link PropertyReferenceException}
33+
*
34+
* @author Oliver Gierke
35+
*/
36+
public class PropertyReferenceExceptionUnitTests {
37+
38+
static final TypeInformation<Sample> TYPE_INFO = ClassTypeInformation.from(Sample.class);
39+
static final List<PropertyPath> NO_PATHS = Collections.emptyList();
40+
41+
public @Rule ExpectedException exception = ExpectedException.none();
42+
43+
@Test
44+
public void rejectsNullPropertyName() {
45+
46+
exception.expect(IllegalArgumentException.class);
47+
exception.expectMessage("name");
48+
49+
new PropertyReferenceException(null, TYPE_INFO, NO_PATHS);
50+
}
51+
52+
@Test
53+
public void rejectsNullType() {
54+
55+
exception.expect(IllegalArgumentException.class);
56+
exception.expectMessage("Type");
57+
58+
new PropertyReferenceException("nme", null, NO_PATHS);
59+
}
60+
61+
@Test
62+
public void rejectsNullPaths() {
63+
64+
exception.expect(IllegalArgumentException.class);
65+
exception.expectMessage("paths");
66+
67+
new PropertyReferenceException("nme", TYPE_INFO, null);
68+
}
69+
70+
/**
71+
* @see DATACMNS-801
72+
*/
73+
@Test
74+
public void exposesPotentialMatch() {
75+
76+
PropertyReferenceException exception = new PropertyReferenceException("nme", TYPE_INFO, NO_PATHS);
77+
78+
Collection<String> matches = exception.getPropertyMatches();
79+
80+
assertThat(matches, hasSize(1));
81+
assertThat(matches, hasItem("name"));
82+
}
83+
84+
static class Sample {
85+
86+
String name;
87+
88+
public String getName() {
89+
return name;
90+
}
91+
92+
public void setName(String name) {
93+
this.name = name;
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)