4141 * A factory implementation to create {@link PersistentPropertyPath} instances in various ways.
4242 *
4343 * @author Oliver Gierke
44+ * @author Christoph Strobl
4445 * @since 2.1
4546 * @soundtrack Cypress Hill - Boom Biddy Bye Bye (Fugees Remix, Unreleased & Revamped)
4647 */
4748class PersistentPropertyPathFactory <E extends PersistentEntity <?, P >, P extends PersistentProperty <P >> {
4849
4950 private static final Predicate <PersistentProperty <? extends PersistentProperty <?>>> IS_ENTITY = PersistentProperty ::isEntity ;
5051
51- private final Map <TypeAndPath , PersistentPropertyPath < P > > propertyPaths = new ConcurrentReferenceHashMap <>();
52+ private final Map <TypeAndPath , PathResolution > propertyPaths = new ConcurrentReferenceHashMap <>();
5253 private final MappingContext <E , P > context ;
5354
5455 public PersistentPropertyPathFactory (MappingContext <E , P > context ) {
@@ -166,7 +167,10 @@ public <T> PersistentPropertyPaths<T, P> from(TypeInformation<T> type, Predicate
166167 }
167168
168169 private PersistentPropertyPath <P > getPersistentPropertyPath (TypeInformation <?> type , String propertyPath ) {
170+ return getPotentiallyCachedPath (type , propertyPath ).getResolvedPath ();
171+ }
169172
173+ private PathResolution getPotentiallyCachedPath (TypeInformation <?> type , String propertyPath ) {
170174 return propertyPaths .computeIfAbsent (TypeAndPath .of (type , propertyPath ),
171175 it -> createPersistentPropertyPath (it .getPath (), it .getType ()));
172176 }
@@ -178,7 +182,7 @@ private PersistentPropertyPath<P> getPersistentPropertyPath(TypeInformation<?> t
178182 * @param type must not be {@literal null}.
179183 * @return
180184 */
181- private PersistentPropertyPath < P > createPersistentPropertyPath (String propertyPath , TypeInformation <?> type ) {
185+ private PathResolution createPersistentPropertyPath (String propertyPath , TypeInformation <?> type ) {
182186
183187 String trimmedPath = propertyPath .trim ();
184188 List <String > parts = trimmedPath .isEmpty () ? Collections .emptyList () : List .of (trimmedPath .split ("\\ ." ));
@@ -196,17 +200,14 @@ private PersistentPropertyPath<P> createPersistentPropertyPath(String propertyPa
196200 Pair <DefaultPersistentPropertyPath <P >, E > pair = getPair (path , iterator , segment , current );
197201
198202 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 );
203204 }
204205
205206 path = pair .getFirst ();
206207 current = pair .getSecond ();
207208 }
208209
209- return path ;
210+ return new PathResolution ( path ) ;
210211 }
211212
212213 @ Nullable
@@ -429,4 +430,44 @@ public int compare(PersistentPropertyPath<?> left, PersistentPropertyPath<?> rig
429430 }
430431 }
431432 }
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+ }
432473}
0 commit comments