1
1
/*
2
- * Copyright 2015 the original author or authors.
2
+ * Copyright 2015-2016 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
17
17
18
18
import java .util .ArrayList ;
19
19
import java .util .Arrays ;
20
+ import java .util .Collections ;
21
+ import java .util .HashMap ;
20
22
import java .util .Iterator ;
21
23
import java .util .List ;
22
24
import java .util .Map ;
25
+ import java .util .Map .Entry ;
26
+ import java .util .Set ;
23
27
import java .util .Stack ;
24
28
import java .util .regex .Pattern ;
25
29
30
+ import org .bson .BasicBSONObject ;
26
31
import org .springframework .data .domain .Example ;
27
- import org .springframework .data .domain .Example .NullHandler ;
28
- import org .springframework .data .domain .Example .StringMatcher ;
29
- import org .springframework .data .domain .PropertySpecifier ;
32
+ import org .springframework .data .domain .ExampleSpec ;
33
+ import org .springframework .data .domain .ExampleSpec .NullHandler ;
34
+ import org .springframework .data .domain .ExampleSpec .PropertyValueTransformer ;
35
+ import org .springframework .data .domain .ExampleSpec .StringMatcher ;
30
36
import org .springframework .data .mapping .PropertyHandler ;
31
37
import org .springframework .data .mapping .context .MappingContext ;
32
38
import org .springframework .data .mongodb .core .mapping .MongoPersistentEntity ;
33
39
import org .springframework .data .mongodb .core .mapping .MongoPersistentProperty ;
34
40
import org .springframework .data .mongodb .core .query .MongoRegexCreator ;
35
41
import org .springframework .data .mongodb .core .query .SerializationUtils ;
42
+ import org .springframework .data .repository .core .support .ExampleSpecAccessor ;
43
+ import org .springframework .data .repository .query .parser .Part .Type ;
36
44
import org .springframework .util .ObjectUtils ;
37
45
import org .springframework .util .StringUtils ;
38
46
41
49
42
50
/**
43
51
* @author Christoph Strobl
52
+ * @author Mark Paluch
44
53
* @since 1.8
45
54
*/
46
55
public class MongoExampleMapper {
47
56
48
57
private final MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ;
49
58
private final MongoConverter converter ;
59
+ private final Map <StringMatcher , Type > stringMatcherPartMapping = new HashMap <StringMatcher , Type >();
50
60
51
61
public MongoExampleMapper (MongoConverter converter ) {
52
62
53
63
this .converter = converter ;
54
64
this .mappingContext = converter .getMappingContext ();
65
+
66
+ stringMatcherPartMapping .put (StringMatcher .EXACT , Type .SIMPLE_PROPERTY );
67
+ stringMatcherPartMapping .put (StringMatcher .CONTAINING , Type .CONTAINING );
68
+ stringMatcherPartMapping .put (StringMatcher .STARTING , Type .STARTING_WITH );
69
+ stringMatcherPartMapping .put (StringMatcher .ENDING , Type .ENDING_WITH );
70
+ stringMatcherPartMapping .put (StringMatcher .REGEX , Type .REGEX );
55
71
}
56
72
57
73
/**
58
74
* Returns the given {@link Example} as {@link DBObject} holding matching values extracted from
59
75
* {@link Example#getProbe()}.
60
- *
76
+ *
61
77
* @param example
62
78
* @return
63
79
* @since 1.8
64
80
*/
65
81
public DBObject getMappedExample (Example <?> example ) {
66
- return getMappedExample (example , mappingContext .getPersistentEntity (example .getSampleType ()));
82
+ return getMappedExample (example , mappingContext .getPersistentEntity (example .getProbeType ()));
67
83
}
68
84
69
85
/**
70
86
* Returns the given {@link Example} as {@link DBObject} holding matching values extracted from
71
87
* {@link Example#getProbe()}.
72
- *
88
+ *
73
89
* @param example
74
90
* @param entity
75
91
* @return
76
92
* @since 1.8
77
93
*/
78
94
public DBObject getMappedExample (Example <?> example , MongoPersistentEntity <?> entity ) {
79
95
80
- DBObject reference = (DBObject ) converter .convertToMongoType (example .getSampleObject ());
96
+ DBObject reference = (DBObject ) converter .convertToMongoType (example .getProbe ());
81
97
82
- if (entity .hasIdProperty () && entity .getIdentifierAccessor (example .getSampleObject ()).getIdentifier () == null ) {
98
+ if (entity .hasIdProperty () && entity .getIdentifierAccessor (example .getProbe ()).getIdentifier () == null ) {
83
99
reference .removeField (entity .getIdProperty ().getFieldName ());
84
100
}
85
101
86
- applyPropertySpecs ("" , reference , example );
102
+ ExampleSpecAccessor exampleSpecAccessor = new ExampleSpecAccessor (example .getExampleSpec ());
103
+
104
+ applyPropertySpecs ("" , reference , example .getProbeType (), exampleSpecAccessor );
87
105
88
- return ObjectUtils .nullSafeEquals (NullHandler .INCLUDE , example .getNullHandler ()) ? reference : new BasicDBObject (
89
- SerializationUtils .flatMap (reference ));
106
+ if (exampleSpecAccessor .isTyped ()) {
107
+ this .converter .getTypeMapper ().writeTypeRestrictions (reference , (Set ) Collections .singleton (example .getResultType ()));
108
+ }
109
+
110
+ return ObjectUtils .nullSafeEquals (NullHandler .INCLUDE , exampleSpecAccessor .getNullHandler ()) ? reference
111
+ : new BasicDBObject (SerializationUtils .flattenMap (reference ));
90
112
}
91
113
92
- private String getMappedPropertyPath (String path , Example <?> example ) {
114
+ private String getMappedPropertyPath (String path , Class <?> probeType ) {
93
115
94
- MongoPersistentEntity <?> entity = mappingContext .getPersistentEntity (example . getSampleType () );
116
+ MongoPersistentEntity <?> entity = mappingContext .getPersistentEntity (probeType );
95
117
96
118
Iterator <String > parts = Arrays .asList (path .split ("\\ ." )).iterator ();
97
119
@@ -136,7 +158,8 @@ public void doWithPersistentProperty(MongoPersistentProperty property) {
136
158
137
159
}
138
160
139
- private void applyPropertySpecs (String path , DBObject source , Example <?> example ) {
161
+ private void applyPropertySpecs (String path , DBObject source , Class <?> probeType ,
162
+ ExampleSpecAccessor exampleSpecAccessor ) {
140
163
141
164
if (!(source instanceof BasicDBObject )) {
142
165
return ;
@@ -147,47 +170,37 @@ private void applyPropertySpecs(String path, DBObject source, Example<?> example
147
170
while (iter .hasNext ()) {
148
171
149
172
Map .Entry <String , Object > entry = iter .next ();
150
-
151
- if (entry .getKey ().equals ("_id" ) && entry .getValue () == null ) {
173
+ String propertyPath = StringUtils .hasText (path ) ? path + "." + entry .getKey () : entry .getKey ();
174
+ String mappedPropertyPath = getMappedPropertyPath (propertyPath , probeType );
175
+
176
+ if (isEmptyIdProperty (entry )) {
152
177
iter .remove ();
153
178
continue ;
154
179
}
155
-
156
- String propertyPath = StringUtils .hasText (path ) ? path + "." + entry .getKey () : entry .getKey ();
157
-
158
- String mappedPropertyPath = getMappedPropertyPath (propertyPath , example );
159
- if (example .isIgnoredPath (propertyPath ) || example .isIgnoredPath (mappedPropertyPath )) {
180
+
181
+ if (exampleSpecAccessor .isIgnoredPath (propertyPath ) || exampleSpecAccessor .isIgnoredPath (mappedPropertyPath )) {
160
182
iter .remove ();
161
183
continue ;
162
184
}
163
185
164
- PropertySpecifier specifier = null ;
165
- StringMatcher stringMatcher = example .getDefaultStringMatcher ();
186
+ StringMatcher stringMatcher = exampleSpecAccessor .getDefaultStringMatcher ();
166
187
Object value = entry .getValue ();
167
- boolean ignoreCase = example . isIngnoreCaseEnabled ();
188
+ boolean ignoreCase = exampleSpecAccessor . isIgnoreCaseEnabled ();
168
189
169
- if (example .hasPropertySpecifiers ()) {
190
+ if (exampleSpecAccessor .hasPropertySpecifiers ()) {
170
191
171
- mappedPropertyPath = example .hasPropertySpecifier (propertyPath ) ? propertyPath : getMappedPropertyPath (
172
- propertyPath , example );
192
+ mappedPropertyPath = exampleSpecAccessor .hasPropertySpecifier (propertyPath ) ? propertyPath
193
+ : getMappedPropertyPath ( propertyPath , probeType );
173
194
174
- specifier = example .getPropertySpecifier (mappedPropertyPath );
175
-
176
- if (specifier != null ) {
177
- if (specifier .hasStringMatcher ()) {
178
- stringMatcher = specifier .getStringMatcher ();
179
- }
180
- if (specifier .getIgnoreCase () != null ) {
181
- ignoreCase = specifier .getIgnoreCase ();
182
- }
183
-
184
- }
195
+ stringMatcher = exampleSpecAccessor .getStringMatcherForPath (mappedPropertyPath );
196
+ ignoreCase = exampleSpecAccessor .isIgnoreCaseForPath (mappedPropertyPath );
185
197
}
186
198
187
199
// TODO: should a PropertySpecifier outrule the later on string matching?
188
- if (specifier != null ) {
200
+ if (exampleSpecAccessor . hasPropertySpecifier ( mappedPropertyPath ) ) {
189
201
190
- value = specifier .transformValue (value );
202
+ PropertyValueTransformer valueTransformer = exampleSpecAccessor .getValueTransformerForPath (mappedPropertyPath );
203
+ value = valueTransformer .convert (value );
191
204
if (value == null ) {
192
205
iter .remove ();
193
206
continue ;
@@ -199,11 +212,15 @@ private void applyPropertySpecs(String path, DBObject source, Example<?> example
199
212
if (entry .getValue () instanceof String ) {
200
213
applyStringMatcher (entry , stringMatcher , ignoreCase );
201
214
} else if (entry .getValue () instanceof BasicDBObject ) {
202
- applyPropertySpecs (propertyPath , (BasicDBObject ) entry .getValue (), example );
215
+ applyPropertySpecs (propertyPath , (BasicDBObject ) entry .getValue (), probeType , exampleSpecAccessor );
203
216
}
204
217
}
205
218
}
206
219
220
+ private boolean isEmptyIdProperty (Entry <String , Object > entry ) {
221
+ return entry .getKey ().equals ("_id" ) && entry .getValue () == null ;
222
+ }
223
+
207
224
private void applyStringMatcher (Map .Entry <String , Object > entry , StringMatcher stringMatcher , boolean ignoreCase ) {
208
225
209
226
BasicDBObject dbo = new BasicDBObject ();
@@ -216,8 +233,8 @@ private void applyStringMatcher(Map.Entry<String, Object> entry, StringMatcher s
216
233
}
217
234
} else {
218
235
219
- String expression = MongoRegexCreator . INSTANCE . toRegularExpression (( String ) entry . getValue (),
220
- stringMatcher . getPartType () );
236
+ Type type = stringMatcherPartMapping . get ( stringMatcher );
237
+ String expression = MongoRegexCreator . INSTANCE . toRegularExpression (( String ) entry . getValue (), type );
221
238
dbo .put ("$regex" , expression );
222
239
entry .setValue (dbo );
223
240
}
@@ -226,4 +243,5 @@ private void applyStringMatcher(Map.Entry<String, Object> entry, StringMatcher s
226
243
dbo .put ("$options" , "i" );
227
244
}
228
245
}
246
+
229
247
}
0 commit comments