Skip to content

Commit c2e3395

Browse files
DATAJPA-218 - Add Predicate based QBE implementation.
We convert a given Example to a set of and combinded Predicates using CriteriaBuilder. Cycles within associations are not allowed and result in an InvalidDataAccessApiUsageException. At this time only SingularAttributes are taken into concern.
1 parent 00bf1f7 commit c2e3395

File tree

12 files changed

+1633
-204
lines changed

12 files changed

+1633
-204
lines changed

src/main/java/org/springframework/data/domain/Example.java

Lines changed: 456 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
* Copyright 2015 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.domain;
17+
18+
import org.springframework.data.domain.Example.StringMatcher;
19+
import org.springframework.util.Assert;
20+
21+
/**
22+
* Define specific property handling for a Dot-Path.
23+
*
24+
* @author Christoph Strobl
25+
*/
26+
public class PropertySpecifier {
27+
28+
private final String path;
29+
30+
private StringMatcher stringMatcher;
31+
private Boolean ignoreCase;
32+
33+
private PropertyValueTransformer valueTransformer;
34+
35+
/**
36+
* Creates new {@link PropertySpecifier} for given path.
37+
*
38+
* @param path Dot-Path to the property. Must not be {@literal null}.
39+
*/
40+
PropertySpecifier(String path) {
41+
42+
Assert.hasText(path, "Path must not be null/empty!");
43+
this.path = path;
44+
}
45+
46+
/**
47+
* Get the properties Dot-Path.
48+
*
49+
* @return never {@literal null}.
50+
*/
51+
public String getPath() {
52+
return path;
53+
}
54+
55+
/**
56+
* Get the {@link StringMatcher}.
57+
*
58+
* @return can be {@literal null}.
59+
*/
60+
public StringMatcher getStringMatcher() {
61+
return stringMatcher;
62+
}
63+
64+
/**
65+
* @return {literal true} in case {@link StringMatcher} defined.
66+
*/
67+
public boolean hasStringMatcher() {
68+
return this.stringMatcher != null;
69+
}
70+
71+
/**
72+
* @return {@literal null} if not set.
73+
*/
74+
public Boolean getIgnoreCase() {
75+
return ignoreCase;
76+
}
77+
78+
/**
79+
* Get the property transformer to be applied.
80+
*
81+
* @return never {@literal null}.
82+
*/
83+
public PropertyValueTransformer getPropertyValueTransformer() {
84+
return valueTransformer == null ? NoOpPropertyValueTransformer.INSTANCE : valueTransformer;
85+
}
86+
87+
/**
88+
* Transforms a given source using the {@link PropertyValueTransformer}.
89+
*
90+
* @param source
91+
* @return
92+
*/
93+
public Object transformValue(Object source) {
94+
return getPropertyValueTransformer().convert(source);
95+
}
96+
97+
/**
98+
* Creates new case ignoring {@link PropertySpecifier} for given path.
99+
*
100+
* @param propertyPath must not be {@literal null}.
101+
* @return
102+
*/
103+
public static PropertySpecifier ignoreCase(String propertyPath) {
104+
return new Builder(propertyPath).ignoreCase().get();
105+
}
106+
107+
/**
108+
* Create new {@link Builder} for specifying {@link PropertySpecifier}.
109+
*
110+
* @param propertyPath must not be {@literal null}.
111+
* @return
112+
*/
113+
public static Builder newPropertySpecifier(String propertyPath) {
114+
return new Builder(propertyPath);
115+
}
116+
117+
/**
118+
* Builder for specifying desired behavior of {@link PropertySpecifier}.
119+
*
120+
* @author Christoph Strobl
121+
*/
122+
public static class Builder {
123+
124+
private PropertySpecifier specifier;
125+
126+
Builder(String path) {
127+
specifier = new PropertySpecifier(path);
128+
}
129+
130+
/**
131+
* Sets the {@link StringMatcher} used for {@link PropertySpecifier}.
132+
*
133+
* @param stringMatcher
134+
* @return
135+
* @see Builder#stringMatcher(StringMatcher)
136+
*/
137+
public Builder with(StringMatcher stringMatcher) {
138+
return stringMatcher(stringMatcher);
139+
}
140+
141+
/**
142+
* Sets the {@link PropertyValueTransformer} used for {@link PropertySpecifier}.
143+
*
144+
* @param valueTransformer
145+
* @return
146+
* @see Builder#valueTransformer(PropertyValueTransformer)
147+
*/
148+
public Builder with(PropertyValueTransformer valueTransformer) {
149+
return valueTransformer(valueTransformer);
150+
}
151+
152+
/**
153+
* Sets the {@link StringMatcher} used for {@link PropertySpecifier}.
154+
*
155+
* @param stringMatcher
156+
* @return
157+
*/
158+
public Builder stringMatcher(StringMatcher stringMatcher) {
159+
return stringMatcher(stringMatcher, specifier.ignoreCase);
160+
}
161+
162+
/**
163+
* Sets the {@link StringMatcher} used for {@link PropertySpecifier}.
164+
*
165+
* @param stringMatcher
166+
* @param ignoreCase
167+
* @return
168+
*/
169+
public Builder stringMatcher(StringMatcher stringMatcher, Boolean ignoreCase) {
170+
171+
specifier.stringMatcher = stringMatcher;
172+
specifier.ignoreCase = ignoreCase;
173+
return this;
174+
}
175+
176+
/**
177+
* @return
178+
*/
179+
public Builder ignoreCase() {
180+
specifier.ignoreCase = Boolean.TRUE;
181+
return this;
182+
}
183+
184+
/**
185+
* Sets the {@link PropertyValueTransformer} used for {@link PropertySpecifier}.
186+
*
187+
* @param valueTransformer
188+
* @return
189+
*/
190+
public Builder valueTransformer(PropertyValueTransformer valueTransformer) {
191+
specifier.valueTransformer = valueTransformer;
192+
return this;
193+
}
194+
195+
/**
196+
* @return {@link PropertySpecifier} as defined.
197+
*/
198+
public PropertySpecifier get() {
199+
return this.specifier;
200+
}
201+
}
202+
203+
/**
204+
* @author Christoph Strobl
205+
*/
206+
static enum NoOpPropertyValueTransformer implements PropertyValueTransformer {
207+
208+
INSTANCE;
209+
210+
@Override
211+
public Object convert(Object source) {
212+
return source;
213+
}
214+
215+
}
216+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2015 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.domain;
17+
18+
import org.springframework.core.convert.converter.Converter;
19+
20+
/**
21+
* @author Christoph Strobl
22+
*/
23+
public interface PropertyValueTransformer extends Converter<Object, Object> {
24+
// TODO: should we use the converter interface directly or not at all?
25+
}

0 commit comments

Comments
 (0)