1818import org .hibernate .validator .internal .metadata .aggregated .CascadingMetaData ;
1919import org .hibernate .validator .internal .metadata .aggregated .ContainerCascadingMetaData ;
2020import org .hibernate .validator .internal .metadata .aggregated .PotentiallyContainerCascadingMetaData ;
21+ import org .hibernate .validator .internal .metadata .aggregated .ReturnValueMetaData ;
22+ import org .hibernate .validator .internal .metadata .aggregated .ValidatableParametersMetaData ;
2123import org .hibernate .validator .internal .metadata .facets .Cascadable ;
2224import org .hibernate .validator .internal .properties .Signature ;
2325import org .hibernate .validator .internal .util .CollectionHelper ;
@@ -26,8 +28,11 @@ public class PredefinedScopeProcessedBeansTrackingStrategy implements ProcessedB
2628
2729 private final Map <Class <?>, Boolean > trackingEnabledForBeans ;
2830
31+ // TODO: signature is just name and parameters so that can clash between different beans.
32+ // with that.. do we even need to track it per signature or since
33+ // we already built the `trackingEnabledForBeans` we can just "inspect" the cascadable as we go
34+ // and check against this `trackingEnabledForBeans` to see if tracking is required ?
2935 private final Map <Signature , Boolean > trackingEnabledForReturnValues ;
30-
3136 private final Map <Signature , Boolean > trackingEnabledForParameters ;
3237
3338 public PredefinedScopeProcessedBeansTrackingStrategy (Map <Class <?>, BeanMetaData <?>> rawBeanMetaDataMap ) {
@@ -198,92 +203,94 @@ private <T> Set<Class<?>> getDirectCascadedBeanClasses(Class<T> beanClass) {
198203 }
199204
200205 for ( Cascadable cascadable : beanMetaData .getCascadables () ) {
201- final CascadingMetaData cascadingMetaData = cascadable .getCascadingMetaData ();
202- if ( cascadingMetaData .isContainer () ) {
203- final ContainerCascadingMetaData containerCascadingMetaData = cascadingMetaData .as ( ContainerCascadingMetaData .class );
204- processContainerCascadingMetaData ( containerCascadingMetaData , directCascadedBeanClasses );
205- }
206- else if ( cascadingMetaData instanceof PotentiallyContainerCascadingMetaData potentiallyContainerCascadingMetaData ) {
207- // if it's a potentially container cascading one, we are "in trouble" as thing can be "almost anything".
208- // TODO: would it be enough to just take the type as defined ?
209- // directCascadedBeanClasses.add( (Class<?>) cascadable.getCascadableType() );
210- //
211- // TODO: or be much more cautious and just assume that it can be "anything":
212- directCascadedBeanClasses .add ( Object .class );
213- }
214- else {
215- // TODO: For now, assume non-container Cascadables are always beans. Truee???
216- directCascadedBeanClasses .add ( typeToClassToProcess ( cascadable .getCascadableType () ) );
217- }
206+ processSingleCascadable ( cascadable , directCascadedBeanClasses );
218207 }
219208 }
220209 return directCascadedBeanClasses ;
221210 }
222211
223- private static void processContainerCascadingMetaData (ContainerCascadingMetaData metaData , Set <Class <?>> directCascadedBeanClasses ) {
224- if ( metaData .isCascading () ) {
225- if ( metaData .getDeclaredTypeParameterIndex () != null ) {
226- if ( metaData .getEnclosingType () instanceof ParameterizedType parameterizedType ) {
227- Type typeArgument = parameterizedType .getActualTypeArguments ()[metaData .getDeclaredTypeParameterIndex ()];
228- if ( typeArgument instanceof Class <?> typeArgumentClass ) {
229- directCascadedBeanClasses .add ( typeArgumentClass );
230- }
231- else if ( typeArgument instanceof TypeVariable <?> typeVariable ) {
232- for ( Type bound : typeVariable .getBounds () ) {
233- directCascadedBeanClasses .add ( typeToClassToProcess ( bound ) );
234- }
212+ private boolean register (Class <?> beanClass , boolean isBeanTrackingEnabled ) {
213+ if ( classToBeanTrackingEnabled .put ( beanClass , isBeanTrackingEnabled ) != null ) {
214+ throw new IllegalStateException ( beanClass .getName () + " registered more than once." );
215+ }
216+ return isBeanTrackingEnabled ;
217+ }
218+ }
219+
220+ private static void processSingleCascadable (Cascadable cascadable , Set <Class <?>> directCascadedBeanClasses ) {
221+ CascadingMetaData cascadingMetaData = cascadable .getCascadingMetaData ();
222+ if ( cascadingMetaData .isContainer () ) {
223+ final ContainerCascadingMetaData containerCascadingMetaData = cascadingMetaData .as ( ContainerCascadingMetaData .class );
224+ processContainerCascadingMetaData ( containerCascadingMetaData , directCascadedBeanClasses );
225+ }
226+ else if ( cascadingMetaData instanceof PotentiallyContainerCascadingMetaData potentiallyContainerCascadingMetaData ) {
227+ // if it's a potentially container cascading one, we are "in trouble" as thing can be "almost anything".
228+ // TODO: would it be enough to just take the type as defined ?
229+ // directCascadedBeanClasses.add( (Class<?>) cascadable.getCascadableType() );
230+ //
231+ // TODO: or be much more cautious and just assume that it can be "anything":
232+ directCascadedBeanClasses .add ( Object .class );
233+ }
234+ else {
235+ // TODO: For now, assume non-container Cascadables are always beans. Truee???
236+ directCascadedBeanClasses .add ( typeToClassToProcess ( cascadable .getCascadableType () ) );
237+ }
238+ }
239+
240+ private static void processContainerCascadingMetaData (ContainerCascadingMetaData metaData , Set <Class <?>> directCascadedBeanClasses ) {
241+ if ( metaData .isCascading () ) {
242+ if ( metaData .getDeclaredTypeParameterIndex () != null ) {
243+ if ( metaData .getEnclosingType () instanceof ParameterizedType parameterizedType ) {
244+ Type typeArgument = parameterizedType .getActualTypeArguments ()[metaData .getDeclaredTypeParameterIndex ()];
245+ if ( typeArgument instanceof Class <?> typeArgumentClass ) {
246+ directCascadedBeanClasses .add ( typeArgumentClass );
247+ }
248+ else if ( typeArgument instanceof TypeVariable <?> typeVariable ) {
249+ for ( Type bound : typeVariable .getBounds () ) {
250+ directCascadedBeanClasses .add ( typeToClassToProcess ( bound ) );
235251 }
236- else if ( typeArgument instanceof WildcardType wildcard ) {
237- for ( Type bound : wildcard .getUpperBounds () ) {
238- directCascadedBeanClasses .add ( typeToClassToProcess ( bound ) );
239- }
240- if ( wildcard .getLowerBounds ().length != 0 ) {
241- // if it's a lower bound ? super smth ... it doesn't matter anymore since it can contain anything so go with object ?
242- directCascadedBeanClasses .add ( Object .class );
243- }
252+ }
253+ else if ( typeArgument instanceof WildcardType wildcard ) {
254+ for ( Type bound : wildcard .getUpperBounds () ) {
255+ directCascadedBeanClasses .add ( typeToClassToProcess ( bound ) );
244256 }
245- else {
246- // TODO: instead of failing, add an Object.class and assume it can be anything ?
247- throw new UnsupportedOperationException ( typeArgument . getClass (). getSimpleName () + " type argument values are not supported." );
257+ if ( wildcard . getLowerBounds (). length != 0 ) {
258+ // if it's a lower bound ? super smth ... it doesn't matter anymore since it can contain anything so go with object ?
259+ directCascadedBeanClasses . add ( Object . class );
248260 }
249261 }
250- }
251- else {
252- // If we do not have the type arguments then we can go though the value extractors,
253- // as they are required to define the `@ExtractedValue(type = ???)` ...
254- // this way we should get the type we want:
255- for ( ValueExtractorDescriptor valueExtractorCandidate : metaData .getValueExtractorCandidates () ) {
256- valueExtractorCandidate .getExtractedType ().ifPresent ( directCascadedBeanClasses ::add );
262+ else {
263+ // TODO: instead of failing, add an Object.class and assume it can be anything ?
264+ throw new UnsupportedOperationException ( typeArgument .getClass ().getSimpleName () + " type argument values are not supported." );
257265 }
258266 }
259267 }
260-
261- if ( metaData .getEnclosingType () instanceof ParameterizedType parameterizedType ) {
262- for ( ContainerCascadingMetaData sub : metaData .getContainerElementTypesCascadingMetaData () ) {
263- processContainerCascadingMetaData ( sub , directCascadedBeanClasses );
268+ else {
269+ // If we do not have the type arguments then we can go though the value extractors,
270+ // as they are required to define the `@ExtractedValue(type = ???)` ...
271+ // this way we should get the type we want:
272+ for ( ValueExtractorDescriptor valueExtractorCandidate : metaData .getValueExtractorCandidates () ) {
273+ valueExtractorCandidate .getExtractedType ().ifPresent ( directCascadedBeanClasses ::add );
264274 }
265275 }
266276 }
267277
268- private static Class <?> typeToClassToProcess (Type type ) {
269- if ( type instanceof Class <?> cascadableClass ) {
270- return cascadableClass ;
271- }
272- else if ( type instanceof ParameterizedType parameterizedType ) {
273- return typeToClassToProcess ( parameterizedType .getRawType () );
274- }
275- else {
276- // TODO: instead of failing, add an Object.class and assume it can be anything ?
277- // return Object.class;
278- throw new UnsupportedOperationException ( type .getClass ().getSimpleName () + " type values are not supported." );
279- }
278+ for ( ContainerCascadingMetaData sub : metaData .getContainerElementTypesCascadingMetaData () ) {
279+ processContainerCascadingMetaData ( sub , directCascadedBeanClasses );
280280 }
281+ }
281282
282- private boolean register (Class <?> beanClass , boolean isBeanTrackingEnabled ) {
283- if ( classToBeanTrackingEnabled .put ( beanClass , isBeanTrackingEnabled ) != null ) {
284- throw new IllegalStateException ( beanClass .getName () + " registered more than once." );
285- }
286- return isBeanTrackingEnabled ;
283+ private static Class <?> typeToClassToProcess (Type type ) {
284+ if ( type instanceof Class <?> cascadableClass ) {
285+ return cascadableClass ;
286+ }
287+ else if ( type instanceof ParameterizedType parameterizedType ) {
288+ return typeToClassToProcess ( parameterizedType .getRawType () );
289+ }
290+ else {
291+ // TODO: instead of failing, add an Object.class and assume it can be anything ?
292+ // return Object.class;
293+ throw new UnsupportedOperationException ( type .getClass ().getSimpleName () + " type values are not supported." );
287294 }
288295 }
289296
@@ -305,6 +312,25 @@ public boolean isEnabledForReturnValue(Signature signature, boolean hasCascadabl
305312 return trackingEnabledForReturnValues .getOrDefault ( signature , true );
306313 }
307314
315+ @ Override
316+ public boolean isEnabledForReturnValue (ReturnValueMetaData returnValueMetaData ) {
317+ if ( !returnValueMetaData .isCascading () ) {
318+ return false ;
319+ }
320+
321+ Set <Class <?>> directCascadedBeanClasses = new HashSet <>();
322+ for ( Cascadable cascadable : returnValueMetaData .getCascadables () ) {
323+ processSingleCascadable ( cascadable , directCascadedBeanClasses );
324+ }
325+ for ( Class <?> directCascadedBeanClass : directCascadedBeanClasses ) {
326+ if ( trackingEnabledForBeans .get ( directCascadedBeanClass ) ) {
327+ return true ;
328+ }
329+ }
330+
331+ return false ;
332+ }
333+
308334 @ Override
309335 public boolean isEnabledForParameters (Signature signature , boolean hasCascadables ) {
310336 if ( !hasCascadables ) {
@@ -314,6 +340,25 @@ public boolean isEnabledForParameters(Signature signature, boolean hasCascadable
314340 return trackingEnabledForParameters .getOrDefault ( signature , true );
315341 }
316342
343+ @ Override
344+ public boolean isEnabledForParameters (ValidatableParametersMetaData parametersMetaData ) {
345+ if ( !parametersMetaData .hasCascadables () ) {
346+ return false ;
347+ }
348+
349+ Set <Class <?>> directCascadedBeanClasses = new HashSet <>();
350+ for ( Cascadable cascadable : parametersMetaData .getCascadables () ) {
351+ processSingleCascadable ( cascadable , directCascadedBeanClasses );
352+ }
353+ for ( Class <?> directCascadedBeanClass : directCascadedBeanClasses ) {
354+ if ( trackingEnabledForBeans .get ( directCascadedBeanClass ) ) {
355+ return true ;
356+ }
357+ }
358+
359+ return false ;
360+ }
361+
317362 @ Override
318363 public void clear () {
319364 trackingEnabledForBeans .clear ();
0 commit comments