1717package org .hibernate .validator .internal .engine ;
1818
1919import java .lang .annotation .ElementType ;
20+ import java .lang .reflect .AccessibleObject ;
2021import java .lang .reflect .Field ;
2122import java .lang .reflect .Member ;
2223import java .lang .reflect .Method ;
2324import java .lang .reflect .Type ;
25+ import java .security .AccessController ;
26+ import java .security .PrivilegedAction ;
2427import java .util .Arrays ;
2528import java .util .Collections ;
2629import java .util .Iterator ;
2730import java .util .List ;
2831import java .util .Map ;
2932import java .util .Set ;
33+ import java .util .concurrent .ConcurrentMap ;
3034import javax .validation .ConstraintValidatorFactory ;
3135import javax .validation .ConstraintViolation ;
3236import javax .validation .MessageInterpolator ;
3741import javax .validation .metadata .BeanDescriptor ;
3842
3943import org .hibernate .validator .internal .engine .groups .Group ;
44+ import org .hibernate .validator .internal .engine .groups .Sequence ;
4045import org .hibernate .validator .internal .engine .groups .ValidationOrder ;
4146import org .hibernate .validator .internal .engine .groups .ValidationOrderGenerator ;
42- import org .hibernate .validator .internal .engine .groups .Sequence ;
4347import org .hibernate .validator .internal .engine .resolver .SingleThreadCachedTraversableResolver ;
4448import org .hibernate .validator .internal .metadata .BeanMetaDataManager ;
4549import org .hibernate .validator .internal .metadata .aggregated .BeanMetaData ;
4650import org .hibernate .validator .internal .metadata .aggregated .MethodMetaData ;
4751import org .hibernate .validator .internal .metadata .aggregated .ParameterMetaData ;
4852import org .hibernate .validator .internal .metadata .core .MetaConstraint ;
53+ import org .hibernate .validator .internal .util .ConcurrentReferenceHashMap ;
4954import org .hibernate .validator .internal .util .Contracts ;
5055import org .hibernate .validator .internal .util .ReflectionHelper ;
5156import org .hibernate .validator .internal .util .TypeHelper ;
5257import org .hibernate .validator .internal .util .logging .Log ;
5358import org .hibernate .validator .internal .util .logging .LoggerFactory ;
59+ import org .hibernate .validator .internal .util .privilegedactions .GetDeclaredField ;
60+ import org .hibernate .validator .internal .util .privilegedactions .GetDeclaredMethod ;
61+ import org .hibernate .validator .internal .util .privilegedactions .SetAccessibility ;
5462import org .hibernate .validator .method .MethodConstraintViolation ;
5563import org .hibernate .validator .method .MethodValidator ;
5664import org .hibernate .validator .method .metadata .TypeDescriptor ;
@@ -108,14 +116,25 @@ public class ValidatorImpl implements Validator, MethodValidator {
108116 */
109117 private final boolean failFast ;
110118
119+ /**
120+ * Keeps an accessible version for each non-accessible member whose value needs to be accessed during validation.
121+ */
122+ private final ConcurrentMap <Member , Member > accessibleMembers ;
123+
111124 public ValidatorImpl (ConstraintValidatorFactory constraintValidatorFactory , MessageInterpolator messageInterpolator , TraversableResolver traversableResolver , BeanMetaDataManager beanMetaDataManager , boolean failFast ) {
112125 this .constraintValidatorFactory = constraintValidatorFactory ;
113126 this .messageInterpolator = messageInterpolator ;
114127 this .traversableResolver = traversableResolver ;
115128 this .beanMetaDataManager = beanMetaDataManager ;
116129 this .failFast = failFast ;
117130
118- validationOrderGenerator = new ValidationOrderGenerator ();
131+ this .validationOrderGenerator = new ValidationOrderGenerator ();
132+
133+ this .accessibleMembers = new ConcurrentReferenceHashMap <Member , Member >(
134+ 100 ,
135+ ConcurrentReferenceHashMap .ReferenceType .SOFT ,
136+ ConcurrentReferenceHashMap .ReferenceType .SOFT
137+ );
119138 }
120139
121140 public final <T > Set <ConstraintViolation <T >> validate (T object , Class <?>... groups ) {
@@ -428,7 +447,9 @@ private <T, U, V> void validateConstraintsForNonDefaultGroup(ValidationContext<T
428447 );
429448 }
430449
431- private <T , U , V > boolean validateConstraint (ValidationContext <T , ?> validationContext , ValueContext <U , V > valueContext , MetaConstraint <?> metaConstraint ) {
450+ private <T , U , V > boolean validateConstraint (ValidationContext <T , ?> validationContext ,
451+ ValueContext <U , V > valueContext ,
452+ MetaConstraint <?> metaConstraint ) {
432453 boolean validationSuccessful = true ;
433454
434455 if ( metaConstraint .getElementType () != ElementType .TYPE ) {
@@ -437,7 +458,7 @@ private <T, U, V> boolean validateConstraint(ValidationContext<T, ?> validationC
437458
438459 if ( isValidationRequired ( validationContext , valueContext , metaConstraint ) ) {
439460 @ SuppressWarnings ("unchecked" )
440- V valueToValidate = (V ) metaConstraint .getValue ( valueContext .getCurrentBean () );
461+ V valueToValidate = (V ) getValue ( metaConstraint .getLocation (). getMember (), valueContext .getCurrentBean () );
441462 valueContext .setCurrentValidatedValue ( valueToValidate );
442463 validationSuccessful = metaConstraint .validateConstraint ( validationContext , valueContext );
443464 }
@@ -461,7 +482,7 @@ private <T, U, V> void validateCascadedConstraints(ValidationContext<T, ?> valid
461482 valueContext .appendNode ( newNode );
462483
463484 if ( isCascadeRequired ( validationContext , valueContext , member ) ) {
464- Object value = ReflectionHelper . getValue ( member , valueContext .getCurrentBean () );
485+ Object value = getValue ( member , valueContext .getCurrentBean () );
465486 if ( value != null ) {
466487 Type type = value .getClass ();
467488 Iterator <?> iter = createIteratorForCascadedValue ( type , value , valueContext );
@@ -752,7 +773,10 @@ private <T, U, V> int validatePropertyForNonDefaultGroup(ValueContext<U, V> valu
752773 if ( isValidationRequired ( validationContext , valueContext , metaConstraint ) ) {
753774 if ( valueContext .getCurrentBean () != null ) {
754775 @ SuppressWarnings ("unchecked" )
755- V valueToValidate = (V ) metaConstraint .getValue ( valueContext .getCurrentBean () );
776+ V valueToValidate = (V ) getValue (
777+ metaConstraint .getLocation ().getMember (),
778+ valueContext .getCurrentBean ()
779+ );
756780 valueContext .setCurrentValidatedValue ( valueToValidate );
757781 }
758782 metaConstraint .validateConstraint ( validationContext , valueContext );
@@ -814,7 +838,10 @@ && isValidationRequired( validationContext, valueContext, metaConstraint ) ) {
814838
815839 if ( valueContext .getCurrentBean () != null ) {
816840 @ SuppressWarnings ("unchecked" )
817- V valueToValidate = (V ) metaConstraint .getValue ( valueContext .getCurrentBean () );
841+ V valueToValidate = (V ) getValue (
842+ metaConstraint .getLocation ().getMember (),
843+ valueContext .getCurrentBean ()
844+ );
818845 valueContext .setCurrentValidatedValue ( valueToValidate );
819846 }
820847 boolean tmp = metaConstraint .validateConstraint ( validationContext , valueContext );
@@ -1157,7 +1184,7 @@ private <T, U, V> ValueContext<U, V> collectMetaConstraintsForPath(Class<T> claz
11571184 for ( Member m : cascadedMembers ) {
11581185 if ( ReflectionHelper .getPropertyName ( m ).equals ( elem .getName () ) ) {
11591186 Type type = ReflectionHelper .typeOf ( m );
1160- newValue = newValue == null ? null : ReflectionHelper . getValue ( m , newValue );
1187+ newValue = newValue == null ? null : getValue ( m , newValue );
11611188 if ( elem .isInIterable () ) {
11621189 if ( newValue != null && elem .getIndex () != null ) {
11631190 newValue = ReflectionHelper .getIndexedValue ( newValue , elem .getIndex () );
@@ -1284,5 +1311,66 @@ private boolean isCascadeRequired(ValidationContext<?, ?> validationContext, Val
12841311 private boolean shouldFailFast (ValidationContext context ) {
12851312 return context .isFailFastModeEnabled () && !context .getFailingConstraints ().isEmpty ();
12861313 }
1314+
1315+ private Object getValue (Member member , Object object ) {
1316+ if ( member == null ) {
1317+ return object ;
1318+ }
1319+
1320+ member = getAccessible ( member );
1321+
1322+ if ( member instanceof Method ) {
1323+ return ReflectionHelper .getValue ( (Method ) member , object );
1324+ }
1325+ else if ( member instanceof Field ) {
1326+ return ReflectionHelper .getValue ( (Field ) member , object );
1327+ }
1328+ return null ;
1329+ }
1330+
1331+ /**
1332+ * Returns an accessible version of the given member. Will be the given member itself in case it is accessible,
1333+ * otherwise a copy which is set accessible. These copies are maintained in the
1334+ * {@link ValidatorImpl#accessibleMembers} cache.
1335+ */
1336+ private Member getAccessible (Member original ) {
1337+ if ( ( (AccessibleObject ) original ).isAccessible () ) {
1338+ return original ;
1339+ }
1340+
1341+ Member member = accessibleMembers .get ( original );
1342+
1343+ if ( member != null ) {
1344+ return member ;
1345+ }
1346+
1347+ Class <?> clazz = original .getDeclaringClass ();
1348+
1349+ if ( original instanceof Field ) {
1350+ member = run ( GetDeclaredField .action ( clazz , original .getName () ) );
1351+ }
1352+ else {
1353+ member = run ( GetDeclaredMethod .action ( clazz , original .getName () ) );
1354+ }
1355+
1356+ run ( SetAccessibility .action ( member ) );
1357+
1358+ Member cached = accessibleMembers .putIfAbsent ( original , member );
1359+ if ( cached != null ) {
1360+ member = cached ;
1361+ }
1362+
1363+ return member ;
1364+ }
1365+
1366+ /**
1367+ * Runs the given privileged action, using a privileged block if required.
1368+ * <p>
1369+ * <b>NOTE:</b> This must never be changed into a publicly available method to avoid execution of arbitrary
1370+ * privileged actions within HV's protection domain.
1371+ */
1372+ private <T > T run (PrivilegedAction <T > action ) {
1373+ return System .getSecurityManager () != null ? AccessController .doPrivileged ( action ) : action .run ();
1374+ }
12871375}
12881376
0 commit comments