-
Notifications
You must be signed in to change notification settings - Fork 572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Explore FreeForm validation v2 #989
base: main
Are you sure you want to change the base?
Changes from 1 commit
f61a93d
80a4bb8
9418a35
415abf7
4a523a8
37d4545
00a7af7
f75e407
ac7835f
92b0696
4e021be
9f1b1da
1807098
8076e67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -453,42 +453,60 @@ private <U> void validateConstraintsForDefaultGroup(BaseBeanValidationContext<?> | |
final BeanMetaData<U> beanMetaData = valueContext.getCurrentBeanMetaData(); | ||
final Map<Class<?>, Class<?>> validatedInterfaces = new HashMap<>(); | ||
|
||
// evaluating the constraints of a bean per class in hierarchy, this is necessary to detect potential default group re-definitions | ||
for ( Class<? super U> clazz : beanMetaData.getClassHierarchy() ) { | ||
BeanMetaData<? super U> hostingBeanMetaData = constraintMetaDataManager.getBeanMetaData( clazz ); | ||
boolean defaultGroupSequenceIsRedefined = hostingBeanMetaData.isDefaultGroupSequenceRedefined(); | ||
|
||
// if the current class redefined the default group sequence, this sequence has to be applied to all the class hierarchy. | ||
if ( defaultGroupSequenceIsRedefined ) { | ||
Iterator<Sequence> defaultGroupSequence = hostingBeanMetaData.getDefaultValidationSequence( valueContext.getCurrentBean() ); | ||
Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getMetaConstraints(); | ||
|
||
while ( defaultGroupSequence.hasNext() ) { | ||
for ( GroupWithInheritance groupOfGroups : defaultGroupSequence.next() ) { | ||
boolean validationSuccessful = true; | ||
|
||
for ( Group defaultSequenceMember : groupOfGroups ) { | ||
validationSuccessful = validateConstraintsForSingleDefaultGroupElement( validationContext, valueContext, validatedInterfaces, clazz, | ||
metaConstraints, defaultSequenceMember ); | ||
} | ||
if ( !validationSuccessful ) { | ||
break; | ||
} | ||
} | ||
boolean defaultGroupSequenceIsRedefined = beanMetaData.isDefaultGroupSequenceRedefined(); | ||
if ( defaultGroupSequenceIsRedefined ) { | ||
validateConstraintsForRedefinedGroupSequence( validationContext, valueContext, validatedInterfaces, beanMetaData.getBeanClass(), beanMetaData ); | ||
validationContext.markCurrentBeanAsProcessed( valueContext ); | ||
} | ||
else { | ||
validateConstraintsForSingleDefaultGroupElement( validationContext, valueContext, validatedInterfaces, beanMetaData.getBeanClass(), beanMetaData.getDirectMetaConstraints(), Group.DEFAULT_GROUP ); | ||
List<Class<? super U>> classHierarchy = beanMetaData.getClassHierarchy(); | ||
|
||
validationContext.markCurrentBeanAsProcessed( valueContext ); | ||
// we start from the second element as first one (the most specific class) was already validated ^ | ||
|
||
// evaluating the constraints of a bean per class in hierarchy, this is necessary to detect potential default group re-definitions | ||
for ( int i = 1; i < classHierarchy.size(); i++ ) { | ||
Class<? super U> clazz = classHierarchy.get( i ); | ||
|
||
BeanMetaData<? super U> hostingBeanMetaData = constraintMetaDataManager.getBeanMetaData( clazz ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As for this part There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree we can skip hierarchy for property holders. Maybe there will be a use case at some point but let's wait to see how it is used. |
||
defaultGroupSequenceIsRedefined = hostingBeanMetaData.isDefaultGroupSequenceRedefined(); | ||
|
||
// if the current class redefined the default group sequence, this sequence has to be applied to all the class hierarchy. | ||
if ( defaultGroupSequenceIsRedefined ) { | ||
validateConstraintsForRedefinedGroupSequence( validationContext, valueContext, validatedInterfaces, clazz, hostingBeanMetaData ); | ||
} | ||
// fast path in case the default group sequence hasn't been redefined | ||
else { | ||
Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getDirectMetaConstraints(); | ||
validateConstraintsForSingleDefaultGroupElement( validationContext, valueContext, validatedInterfaces, clazz, metaConstraints, Group.DEFAULT_GROUP ); | ||
} | ||
|
||
validationContext.markCurrentBeanAsProcessed( valueContext ); | ||
|
||
// all constraints in the hierarchy has been validated, stop validation. | ||
if ( defaultGroupSequenceIsRedefined ) { | ||
break; | ||
} | ||
} | ||
// fast path in case the default group sequence hasn't been redefined | ||
else { | ||
Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getDirectMetaConstraints(); | ||
validateConstraintsForSingleDefaultGroupElement( validationContext, valueContext, validatedInterfaces, clazz, metaConstraints, | ||
Group.DEFAULT_GROUP ); | ||
} | ||
} | ||
} | ||
|
||
validationContext.markCurrentBeanAsProcessed( valueContext ); | ||
private <U> void validateConstraintsForRedefinedGroupSequence(BaseBeanValidationContext<?> validationContext, ValueContext<U, Object> valueContext, Map<Class<?>, Class<?>> validatedInterfaces, Class<? super U> clazz, BeanMetaData<? super U> hostingBeanMetaData) { | ||
Iterator<Sequence> defaultGroupSequence = hostingBeanMetaData.getDefaultValidationSequence( valueContext.getCurrentBean() ); | ||
Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getMetaConstraints(); | ||
|
||
// all constraints in the hierarchy has been validated, stop validation. | ||
if ( defaultGroupSequenceIsRedefined ) { | ||
break; | ||
while ( defaultGroupSequence.hasNext() ) { | ||
for ( GroupWithInheritance groupOfGroups : defaultGroupSequence.next() ) { | ||
boolean validationSuccessful = true; | ||
|
||
for ( Group defaultSequenceMember : groupOfGroups ) { | ||
validationSuccessful = validateConstraintsForSingleDefaultGroupElement( validationContext, valueContext, validatedInterfaces, clazz, | ||
metaConstraints, defaultSequenceMember ); | ||
} | ||
if ( !validationSuccessful ) { | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I plan to make
BeanMetaData
an abstract class with regular and property holder impls. Then in case of property holder there will be nothing else but the property holder class in this list.Also note the change itself. Before this we were accessing a map to get the metadata that we already have. With this we remove that one additional map access.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain the rationale of this change?
It's hard to see the difference, considering all the method is rewritten in the diff.
Once you got this cleared, I think I'll merge it separately (and probably run a JMH benchmark to check everything is OK).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah ... Let me try to explain how I got here. The main "problem" that I was trying to "solve" was to reduce the number of places where
constraintMetaDataManager.getBeanMetaData( clazz );
is called. In case of property holders we cannot use such call And that's why for example in case of cascadebles I've moved such call into metadata class. In this particular place except the call for metadata itself we also access the metadata for the "most specific" class twice.We already have the metadata from the context here -
BeanMetaData<U> beanMetaData = valueContext.getCurrentBeanMetaData()
. But then in the loopfor ( Class<? super U> clazz : beanMetaData.getClassHierarchy() )
we would get the beans class as a first element and try to get that same metadata again -BeanMetaData<? super U> hostingBeanMetaData = constraintMetaDataManager.getBeanMetaData( clazz );
Hence to skip this additional metadata retrieval I've broken the method into two parts - first one will work with the existing "current" metadata
valueContext.getCurrentBeanMetaData()
and in the second part we iterate through the bean class hierarchy skipping the first element which is the bean class.I also remember running JMH tests for these changes and the results were almost identical.
In the end this change gives us:
ValidtorImpl
Now thinking about wrapping the
String mappingName
or beans class into wrapper ... we might end up not needing this at all. As we would then, most likely, have thegetClassHierarchy()
method return the wrappers. Or even maybe return the metadata right away, instead of simply returning classes.