50
50
import com .mongodb .DBObject ;
51
51
52
52
/**
53
+ * Mapper from {@link Example} to a query {@link DBObject}.
54
+ *
53
55
* @author Christoph Strobl
54
56
* @author Mark Paluch
55
57
* @since 1.8
58
+ * @see Example
59
+ * @see org.springframework.data.domain.ExampleMatcher
56
60
*/
57
61
public class MongoExampleMapper {
58
62
59
63
private final MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ;
60
64
private final MongoConverter converter ;
61
65
private final Map <StringMatcher , Type > stringMatcherPartMapping = new HashMap <StringMatcher , Type >();
62
66
67
+ /**
68
+ * Create a new {@link MongoTypeMapper} given {@link MongoConverter}.
69
+ *
70
+ * @param converter must not be {@literal null}.
71
+ */
63
72
public MongoExampleMapper (MongoConverter converter ) {
64
73
65
74
this .converter = converter ;
@@ -101,8 +110,10 @@ public DBObject getMappedExample(Example<?> example, MongoPersistentEntity<?> en
101
110
102
111
DBObject reference = (DBObject ) converter .convertToMongoType (example .getProbe ());
103
112
104
- if (entity .hasIdProperty () && ClassUtils .isAssignable (entity .getType (), example .getProbeType ())) {
105
- if (entity .getIdentifierAccessor (example .getProbe ()).getIdentifier () == null ) {reference .removeField (entity .getIdProperty ().getFieldName ());}
113
+ if (entity .hasIdProperty () && ClassUtils .isAssignable (entity .getType (), example .getProbeType ())) {
114
+ if (entity .getIdentifierAccessor (example .getProbe ()).getIdentifier () == null ) {
115
+ reference .removeField (entity .getIdProperty ().getFieldName ());
116
+ }
106
117
}
107
118
108
119
ExampleMatcherAccessor matcherAccessor = new ExampleMatcherAccessor (example .getMatcher ());
@@ -116,28 +127,63 @@ public DBObject getMappedExample(Example<?> example, MongoPersistentEntity<?> en
116
127
return updateTypeRestrictions (result , example );
117
128
}
118
129
119
- private static DBObject orConcatenate (DBObject source ) {
120
-
121
- List <DBObject > foo = new ArrayList <DBObject >(source .keySet ().size ());
130
+ private void applyPropertySpecs (String path , DBObject source , Class <?> probeType ,
131
+ ExampleMatcherAccessor exampleSpecAccessor ) {
122
132
123
- for ( String key : source . keySet ( )) {
124
- foo . add ( new BasicDBObject ( key , source . get ( key ))) ;
133
+ if (!( source instanceof BasicDBObject )) {
134
+ return ;
125
135
}
126
136
127
- return new BasicDBObject ("$or" , foo );
128
- }
137
+ Iterator <Map .Entry <String , Object >> iter = ((BasicDBObject ) source ).entrySet ().iterator ();
129
138
130
- private Set < Class <?>> getTypesToMatch ( Example <?> example ) {
139
+ while ( iter . hasNext () ) {
131
140
132
- Set <Class <?>> types = new HashSet <Class <?>>();
141
+ Map .Entry <String , Object > entry = iter .next ();
142
+ String propertyPath = StringUtils .hasText (path ) ? path + "." + entry .getKey () : entry .getKey ();
143
+ String mappedPropertyPath = getMappedPropertyPath (propertyPath , probeType );
133
144
134
- for ( TypeInformation <?> reference : mappingContext . getManagedTypes ( )) {
135
- if ( example . getProbeType (). isAssignableFrom ( reference . getType ())) {
136
- types . add ( reference . getType ()) ;
145
+ if ( isEmptyIdProperty ( entry )) {
146
+ iter . remove ();
147
+ continue ;
137
148
}
138
- }
139
149
140
- return types ;
150
+ if (exampleSpecAccessor .isIgnoredPath (propertyPath ) || exampleSpecAccessor .isIgnoredPath (mappedPropertyPath )) {
151
+ iter .remove ();
152
+ continue ;
153
+ }
154
+
155
+ StringMatcher stringMatcher = exampleSpecAccessor .getDefaultStringMatcher ();
156
+ Object value = entry .getValue ();
157
+ boolean ignoreCase = exampleSpecAccessor .isIgnoreCaseEnabled ();
158
+
159
+ if (exampleSpecAccessor .hasPropertySpecifiers ()) {
160
+
161
+ mappedPropertyPath = exampleSpecAccessor .hasPropertySpecifier (propertyPath ) ? propertyPath
162
+ : getMappedPropertyPath (propertyPath , probeType );
163
+
164
+ stringMatcher = exampleSpecAccessor .getStringMatcherForPath (mappedPropertyPath );
165
+ ignoreCase = exampleSpecAccessor .isIgnoreCaseForPath (mappedPropertyPath );
166
+ }
167
+
168
+ // TODO: should a PropertySpecifier outrule the later on string matching?
169
+ if (exampleSpecAccessor .hasPropertySpecifier (mappedPropertyPath )) {
170
+
171
+ PropertyValueTransformer valueTransformer = exampleSpecAccessor .getValueTransformerForPath (mappedPropertyPath );
172
+ value = valueTransformer .convert (value );
173
+ if (value == null ) {
174
+ iter .remove ();
175
+ continue ;
176
+ }
177
+
178
+ entry .setValue (value );
179
+ }
180
+
181
+ if (entry .getValue () instanceof String ) {
182
+ applyStringMatcher (entry , stringMatcher , ignoreCase );
183
+ } else if (entry .getValue () instanceof BasicDBObject ) {
184
+ applyPropertySpecs (propertyPath , (BasicDBObject ) entry .getValue (), probeType , exampleSpecAccessor );
185
+ }
186
+ }
141
187
}
142
188
143
189
private String getMappedPropertyPath (String path , Class <?> probeType ) {
@@ -171,6 +217,7 @@ public void doWithPersistentProperty(MongoPersistentProperty property) {
171
217
if (stack .isEmpty ()) {
172
218
return "" ;
173
219
}
220
+
174
221
prop = stack .pop ();
175
222
}
176
223
@@ -184,69 +231,57 @@ public void doWithPersistentProperty(MongoPersistentProperty property) {
184
231
}
185
232
186
233
return StringUtils .collectionToDelimitedString (resultParts , "." );
187
-
188
234
}
189
235
190
- private void applyPropertySpecs (String path , DBObject source , Class <?> probeType ,
191
- ExampleMatcherAccessor exampleSpecAccessor ) {
192
-
193
- if (!(source instanceof BasicDBObject )) {
194
- return ;
195
- }
196
-
197
- Iterator <Map .Entry <String , Object >> iter = ((BasicDBObject ) source ).entrySet ().iterator ();
236
+ private DBObject updateTypeRestrictions (DBObject query , Example example ) {
198
237
199
- while ( iter . hasNext ()) {
238
+ DBObject result = new BasicDBObject ();
200
239
201
- Map .Entry <String , Object > entry = iter .next ();
202
- String propertyPath = StringUtils .hasText (path ) ? path + "." + entry .getKey () : entry .getKey ();
203
- String mappedPropertyPath = getMappedPropertyPath (propertyPath , probeType );
240
+ if (isTypeRestricting (example .getMatcher ())) {
204
241
205
- if ( isEmptyIdProperty ( entry )) {
206
- iter . remove ( );
207
- continue ;
208
- }
242
+ result . putAll ( query );
243
+ this . converter . getTypeMapper (). writeTypeRestrictions ( result , getTypesToMatch ( example ) );
244
+ return result ;
245
+ }
209
246
210
- if ( exampleSpecAccessor . isIgnoredPath ( propertyPath ) || exampleSpecAccessor . isIgnoredPath ( mappedPropertyPath )) {
211
- iter . remove ();
212
- continue ;
247
+ for ( String key : query . keySet ( )) {
248
+ if (! this . converter . getTypeMapper (). isTypeKey ( key )) {
249
+ result . put ( key , query . get ( key )) ;
213
250
}
251
+ }
214
252
215
- StringMatcher stringMatcher = exampleSpecAccessor .getDefaultStringMatcher ();
216
- Object value = entry .getValue ();
217
- boolean ignoreCase = exampleSpecAccessor .isIgnoreCaseEnabled ();
253
+ return result ;
254
+ }
218
255
219
- if ( exampleSpecAccessor . hasPropertySpecifiers () ) {
256
+ private boolean isTypeRestricting ( ExampleMatcher matcher ) {
220
257
221
- mappedPropertyPath = exampleSpecAccessor .hasPropertySpecifier (propertyPath ) ? propertyPath
222
- : getMappedPropertyPath (propertyPath , probeType );
258
+ if (matcher .getIgnoredPaths ().isEmpty ()) {
259
+ return true ;
260
+ }
223
261
224
- stringMatcher = exampleSpecAccessor .getStringMatcherForPath (mappedPropertyPath );
225
- ignoreCase = exampleSpecAccessor .isIgnoreCaseForPath (mappedPropertyPath );
262
+ for (String path : matcher .getIgnoredPaths ()) {
263
+ if (this .converter .getTypeMapper ().isTypeKey (path )) {
264
+ return false ;
226
265
}
266
+ }
227
267
228
- // TODO: should a PropertySpecifier outrule the later on string matching?
229
- if ( exampleSpecAccessor . hasPropertySpecifier ( mappedPropertyPath )) {
268
+ return true ;
269
+ }
230
270
231
- PropertyValueTransformer valueTransformer = exampleSpecAccessor .getValueTransformerForPath (mappedPropertyPath );
232
- value = valueTransformer .convert (value );
233
- if (value == null ) {
234
- iter .remove ();
235
- continue ;
236
- }
271
+ private Set <Class <?>> getTypesToMatch (Example <?> example ) {
237
272
238
- entry .setValue (value );
239
- }
273
+ Set <Class <?>> types = new HashSet <Class <?>>();
240
274
241
- if (entry .getValue () instanceof String ) {
242
- applyStringMatcher (entry , stringMatcher , ignoreCase );
243
- } else if (entry .getValue () instanceof BasicDBObject ) {
244
- applyPropertySpecs (propertyPath , (BasicDBObject ) entry .getValue (), probeType , exampleSpecAccessor );
275
+ for (TypeInformation <?> reference : mappingContext .getManagedTypes ()) {
276
+ if (example .getProbeType ().isAssignableFrom (reference .getType ())) {
277
+ types .add (reference .getType ());
245
278
}
246
279
}
280
+
281
+ return types ;
247
282
}
248
283
249
- private boolean isEmptyIdProperty (Entry <String , Object > entry ) {
284
+ private static boolean isEmptyIdProperty (Entry <String , Object > entry ) {
250
285
return entry .getKey ().equals ("_id" ) && entry .getValue () == null ;
251
286
}
252
287
@@ -273,38 +308,14 @@ private void applyStringMatcher(Map.Entry<String, Object> entry, StringMatcher s
273
308
}
274
309
}
275
310
276
- private DBObject updateTypeRestrictions (DBObject query , Example example ) {
277
-
278
- DBObject result = new BasicDBObject ();
279
-
280
- if (isTypeRestricting (example .getMatcher ())) {
281
-
282
- result .putAll (query );
283
- this .converter .getTypeMapper ().writeTypeRestrictions (result , getTypesToMatch (example ));
284
- return result ;
285
- }
286
-
287
- for (String key : query .keySet ()) {
288
- if (!this .converter .getTypeMapper ().isTypeKey (key )) {
289
- result .put (key , query .get (key ));
290
- }
291
- }
292
-
293
- return result ;
294
- }
295
-
296
- private boolean isTypeRestricting (ExampleMatcher matcher ) {
311
+ private static DBObject orConcatenate (DBObject source ) {
297
312
298
- if (matcher .getIgnoredPaths ().isEmpty ()) {
299
- return true ;
300
- }
313
+ List <DBObject > or = new ArrayList <DBObject >(source .keySet ().size ());
301
314
302
- for (String path : matcher .getIgnoredPaths ()) {
303
- if (this .converter .getTypeMapper ().isTypeKey (path )) {
304
- return false ;
305
- }
315
+ for (String key : source .keySet ()) {
316
+ or .add (new BasicDBObject (key , source .get (key )));
306
317
}
307
318
308
- return true ;
319
+ return new BasicDBObject ( "$or" , or ) ;
309
320
}
310
321
}
0 commit comments