41
41
* A factory implementation to create {@link PersistentPropertyPath} instances in various ways.
42
42
*
43
43
* @author Oliver Gierke
44
+ * @author Christoph Strobl
44
45
* @since 2.1
45
46
* @soundtrack Cypress Hill - Boom Biddy Bye Bye (Fugees Remix, Unreleased & Revamped)
46
47
*/
47
48
class PersistentPropertyPathFactory <E extends PersistentEntity <?, P >, P extends PersistentProperty <P >> {
48
49
49
50
private static final Predicate <PersistentProperty <? extends PersistentProperty <?>>> IS_ENTITY = PersistentProperty ::isEntity ;
50
51
51
- private final Map <TypeAndPath , PersistentPropertyPath < P > > propertyPaths = new ConcurrentReferenceHashMap <>();
52
+ private final Map <TypeAndPath , PathResolution > propertyPaths = new ConcurrentReferenceHashMap <>();
52
53
private final MappingContext <E , P > context ;
53
54
54
55
public PersistentPropertyPathFactory (MappingContext <E , P > context ) {
@@ -166,7 +167,10 @@ public <T> PersistentPropertyPaths<T, P> from(TypeInformation<T> type, Predicate
166
167
}
167
168
168
169
private PersistentPropertyPath <P > getPersistentPropertyPath (TypeInformation <?> type , String propertyPath ) {
170
+ return getPotentiallyCachedPath (type , propertyPath ).getResolvedPath ();
171
+ }
169
172
173
+ private PathResolution getPotentiallyCachedPath (TypeInformation <?> type , String propertyPath ) {
170
174
return propertyPaths .computeIfAbsent (TypeAndPath .of (type , propertyPath ),
171
175
it -> createPersistentPropertyPath (it .getPath (), it .getType ()));
172
176
}
@@ -178,7 +182,7 @@ private PersistentPropertyPath<P> getPersistentPropertyPath(TypeInformation<?> t
178
182
* @param type must not be {@literal null}.
179
183
* @return
180
184
*/
181
- private PersistentPropertyPath < P > createPersistentPropertyPath (String propertyPath , TypeInformation <?> type ) {
185
+ private PathResolution createPersistentPropertyPath (String propertyPath , TypeInformation <?> type ) {
182
186
183
187
String trimmedPath = propertyPath .trim ();
184
188
List <String > parts = trimmedPath .isEmpty () ? Collections .emptyList () : List .of (trimmedPath .split ("\\ ." ));
@@ -196,17 +200,14 @@ private PersistentPropertyPath<P> createPersistentPropertyPath(String propertyPa
196
200
Pair <DefaultPersistentPropertyPath <P >, E > pair = getPair (path , iterator , segment , current );
197
201
198
202
if (pair == null ) {
199
-
200
- String source = StringUtils .collectionToDelimitedString (parts , "." );
201
-
202
- throw new InvalidPersistentPropertyPath (source , type , segment , currentPath );
203
+ return new PathResolution (parts , segment , type , currentPath );
203
204
}
204
205
205
206
path = pair .getFirst ();
206
207
current = pair .getSecond ();
207
208
}
208
209
209
- return path ;
210
+ return new PathResolution ( path ) ;
210
211
}
211
212
212
213
@ Nullable
@@ -429,4 +430,44 @@ public int compare(PersistentPropertyPath<?> left, PersistentPropertyPath<?> rig
429
430
}
430
431
}
431
432
}
433
+
434
+ /**
435
+ * Wrapper around {@link PersistentPropertyPath} that allows them to be cached. Retains behaviour be throwing
436
+ * {@link InvalidPersistentPropertyPath} on access of {@link #getResolvedPath()} if no corresponding property was
437
+ * found.
438
+ */
439
+ private static class PathResolution {
440
+
441
+ private final PersistentPropertyPath <?> path ;
442
+ private final boolean resolvable ;
443
+ private String source , segment ;
444
+ private TypeInformation <?> type ;
445
+
446
+ public PathResolution (PersistentPropertyPath <?> path ) {
447
+
448
+ this .path = path ;
449
+ this .resolvable = true ;
450
+ }
451
+
452
+ PathResolution (List <String > parts , String segment , TypeInformation <?> type , PersistentPropertyPath <?> path ) {
453
+
454
+ this .source = StringUtils .collectionToDelimitedString (parts , "." );
455
+ this .segment = segment ;
456
+ this .type = type ;
457
+ this .path = path ;
458
+ this .resolvable = false ;
459
+ }
460
+
461
+ /**
462
+ * @return the path if available.
463
+ * @throws InvalidPersistentPropertyPath when the path could not be resolved to an actual property
464
+ */
465
+ PersistentPropertyPath getResolvedPath () {
466
+
467
+ if (resolvable ) {
468
+ return path ;
469
+ }
470
+ throw new InvalidPersistentPropertyPath (source , type , segment , path );
471
+ }
472
+ }
432
473
}
0 commit comments