34
34
35
35
import org .springframework .dao .InvalidDataAccessApiUsageException ;
36
36
import org .springframework .data .domain .Example ;
37
- import org .springframework .data .domain .Example .NullHandler ;
37
+ import org .springframework .data .domain .ExampleSpec ;
38
+ import org .springframework .data .repository .core .support .ExampleSpecAccessor ;
38
39
import org .springframework .data .util .DirectFieldAccessFallbackBeanWrapper ;
39
40
import org .springframework .orm .jpa .JpaSystemException ;
40
41
import org .springframework .util .Assert ;
48
49
* The builder includes any {@link SingularAttribute} of the {@link Example#getProbe()} applying {@link String} and
49
50
* {@literal null} matching strategies configured on the {@link Example}. Ignored paths are no matter of their actual
50
51
* value not considered. <br />
51
- *
52
+ *
52
53
* @author Christoph Strobl
54
+ * @author Mark Paluch
53
55
* @since 1.10
54
56
*/
55
57
public class QueryByExamplePredicateBuilder {
@@ -63,7 +65,7 @@ public class QueryByExamplePredicateBuilder {
63
65
64
66
/**
65
67
* Extract the {@link Predicate} representing the {@link Example}.
66
- *
68
+ *
67
69
* @param root must not be {@literal null}.
68
70
* @param cb must not be {@literal null}.
69
71
* @param example must not be {@literal null}.
@@ -73,13 +75,14 @@ public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Examp
73
75
74
76
Assert .notNull (root , "Root must not be null!" );
75
77
Assert .notNull (cb , "CriteriaBuilder must not be null!" );
76
- Assert .notNull (example , "Root must not be null!" );
78
+ Assert .notNull (example , "Example must not be null!" );
77
79
78
- List <Predicate > predicates = getPredicates ("" , cb , root , root .getModel (), example .getSampleObject (), example ,
79
- new PathNode ("root" , null , example .getSampleObject ()));
80
+ List <Predicate > predicates = getPredicates ("" , cb , root , root .getModel (), example .getProbe (),
81
+ example .getProbeType (), new ExampleSpecAccessor (example .getExampleSpec ()),
82
+ new PathNode ("root" , null , example .getProbe ()));
80
83
81
84
if (predicates .isEmpty ()) {
82
- return cb .isTrue (cb .literal (false ));
85
+ return cb .isTrue (cb .literal (true ));
83
86
}
84
87
85
88
if (predicates .size () == 1 ) {
@@ -90,8 +93,8 @@ public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Examp
90
93
}
91
94
92
95
@ SuppressWarnings ({ "rawtypes" , "unchecked" })
93
- static List <Predicate > getPredicates (String path , CriteriaBuilder cb , Path <?> from , ManagedType <?> type ,
94
- Object value , Example <?> example , PathNode currentNode ) {
96
+ static List <Predicate > getPredicates (String path , CriteriaBuilder cb , Path <?> from , ManagedType <?> type , Object value ,
97
+ Class <?> probeType , ExampleSpecAccessor exampleAccessor , PathNode currentNode ) {
95
98
96
99
List <Predicate > predicates = new ArrayList <Predicate >();
97
100
DirectFieldAccessFallbackBeanWrapper beanWrapper = new DirectFieldAccessFallbackBeanWrapper (value );
@@ -100,16 +103,16 @@ static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> fr
100
103
101
104
String currentPath = !StringUtils .hasText (path ) ? attribute .getName () : path + "." + attribute .getName ();
102
105
103
- if (example .isIgnoredPath (currentPath )) {
106
+ if (exampleAccessor .isIgnoredPath (currentPath )) {
104
107
continue ;
105
108
}
106
109
107
- Object attributeValue = example .getValueTransformerForPath (currentPath ). convert (
108
- beanWrapper .getPropertyValue (attribute .getName ()));
110
+ Object attributeValue = exampleAccessor .getValueTransformerForPath (currentPath )
111
+ . convert ( beanWrapper .getPropertyValue (attribute .getName ()));
109
112
110
113
if (attributeValue == null ) {
111
114
112
- if (example .getNullHandler ().equals (NullHandler .INCLUDE )) {
115
+ if (exampleAccessor .getNullHandler ().equals (ExampleSpec . NullHandler .INCLUDE )) {
113
116
predicates .add (cb .isNull (from .get (attribute )));
114
117
}
115
118
continue ;
@@ -118,39 +121,39 @@ static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> fr
118
121
if (attribute .getPersistentAttributeType ().equals (PersistentAttributeType .EMBEDDED )) {
119
122
120
123
predicates .addAll (getPredicates (currentPath , cb , from .get (attribute .getName ()),
121
- (ManagedType <?>) attribute .getType (), attributeValue , example , currentNode ));
124
+ (ManagedType <?>) attribute .getType (), attributeValue , probeType , exampleAccessor , currentNode ));
122
125
continue ;
123
126
}
124
127
125
128
if (isAssociation (attribute )) {
126
129
127
130
if (!(from instanceof From )) {
128
- throw new JpaSystemException (new IllegalArgumentException (String . format (
129
- "Unexpected path type for %s. Found % where From.class was expected." , currentPath , from )));
131
+ throw new JpaSystemException (new IllegalArgumentException (
132
+ String . format ( "Unexpected path type for %s. Found % where From.class was expected." , currentPath , from )));
130
133
}
131
134
132
135
PathNode node = currentNode .add (attribute .getName (), attributeValue );
133
136
if (node .spansCycle ()) {
134
- throw new InvalidDataAccessApiUsageException (String . format (
135
- "Path '%s' from root %s must not span a cyclic property reference!\r \n %s" , currentPath ,
136
- ClassUtils .getShortName (example . getSampleType () ), node ));
137
+ throw new InvalidDataAccessApiUsageException (
138
+ String . format ( "Path '%s' from root %s must not span a cyclic property reference!\r \n %s" , currentPath ,
139
+ ClassUtils .getShortName (probeType ), node ));
137
140
}
138
141
139
142
predicates .addAll (getPredicates (currentPath , cb , ((From <?, ?>) from ).join (attribute .getName ()),
140
- (ManagedType <?>) attribute .getType (), attributeValue , example , node ));
143
+ (ManagedType <?>) attribute .getType (), attributeValue , probeType , exampleAccessor , node ));
141
144
142
145
continue ;
143
146
}
144
147
145
148
if (attribute .getJavaType ().equals (String .class )) {
146
149
147
150
Expression <String > expression = from .get (attribute );
148
- if (example .isIgnoreCaseForPath (currentPath )) {
151
+ if (exampleAccessor .isIgnoreCaseForPath (currentPath )) {
149
152
expression = cb .lower (expression );
150
153
attributeValue = attributeValue .toString ().toLowerCase ();
151
154
}
152
155
153
- switch (example .getStringMatcherForPath (currentPath )) {
156
+ switch (exampleAccessor .getStringMatcherForPath (currentPath )) {
154
157
155
158
case DEFAULT :
156
159
case EXACT :
@@ -166,8 +169,8 @@ static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> fr
166
169
predicates .add (cb .like (expression , "%" + attributeValue ));
167
170
break ;
168
171
default :
169
- throw new IllegalArgumentException ("Unsupported StringMatcher "
170
- + example .getStringMatcherForPath (currentPath ));
172
+ throw new IllegalArgumentException (
173
+ "Unsupported StringMatcher " + exampleAccessor .getStringMatcherForPath (currentPath ));
171
174
}
172
175
} else {
173
176
predicates .add (cb .equal (from .get (attribute ), attributeValue ));
@@ -184,7 +187,7 @@ private static boolean isAssociation(Attribute<?, ?> attribute) {
184
187
/**
185
188
* {@link PathNode} is used to dynamically grow a directed graph structure that allows to detect cycles within its
186
189
* direct predecessor nodes by comparing parent node values using {@link System#identityHashCode(Object)}.
187
- *
190
+ *
188
191
* @author Christoph Strobl
189
192
*/
190
193
private static class PathNode {
0 commit comments