Skip to content

Commit ab21ca9

Browse files
gunnarmorlinghferentschik
authored andcommitted
HV-912 Not exposing accessible-made members
1 parent ea88f45 commit ab21ca9

File tree

4 files changed

+97
-61
lines changed

4 files changed

+97
-61
lines changed

engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@
1717
package org.hibernate.validator.internal.engine;
1818

1919
import java.lang.annotation.ElementType;
20+
import java.lang.reflect.AccessibleObject;
2021
import java.lang.reflect.Field;
2122
import java.lang.reflect.Member;
2223
import java.lang.reflect.Method;
2324
import java.lang.reflect.Type;
25+
import java.security.AccessController;
26+
import java.security.PrivilegedAction;
2427
import java.util.Arrays;
2528
import java.util.Collections;
2629
import java.util.Iterator;
2730
import java.util.List;
2831
import java.util.Map;
2932
import java.util.Set;
33+
import java.util.concurrent.ConcurrentMap;
3034
import javax.validation.ConstraintValidatorFactory;
3135
import javax.validation.ConstraintViolation;
3236
import javax.validation.MessageInterpolator;
@@ -37,20 +41,24 @@
3741
import javax.validation.metadata.BeanDescriptor;
3842

3943
import org.hibernate.validator.internal.engine.groups.Group;
44+
import org.hibernate.validator.internal.engine.groups.Sequence;
4045
import org.hibernate.validator.internal.engine.groups.ValidationOrder;
4146
import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
42-
import org.hibernate.validator.internal.engine.groups.Sequence;
4347
import org.hibernate.validator.internal.engine.resolver.SingleThreadCachedTraversableResolver;
4448
import org.hibernate.validator.internal.metadata.BeanMetaDataManager;
4549
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
4650
import org.hibernate.validator.internal.metadata.aggregated.MethodMetaData;
4751
import org.hibernate.validator.internal.metadata.aggregated.ParameterMetaData;
4852
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
53+
import org.hibernate.validator.internal.util.ConcurrentReferenceHashMap;
4954
import org.hibernate.validator.internal.util.Contracts;
5055
import org.hibernate.validator.internal.util.ReflectionHelper;
5156
import org.hibernate.validator.internal.util.TypeHelper;
5257
import org.hibernate.validator.internal.util.logging.Log;
5358
import 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;
5462
import org.hibernate.validator.method.MethodConstraintViolation;
5563
import org.hibernate.validator.method.MethodValidator;
5664
import 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

engine/src/main/java/org/hibernate/validator/internal/engine/resolver/DefaultTraversableResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ private void detectJPA() {
9999
// unfortunately there are several incomplete implementations out there (see HV-374)
100100
try {
101101
Object persistence = run( NewInstance.action( persistenceClass, "persistence provider" ) );
102-
ReflectionHelper.getValue(persistenceUtilGetter, persistence );
102+
ReflectionHelper.getValue( persistenceUtilGetter, persistence );
103103
}
104104
catch ( Exception e ) {
105105
log.debugf(

engine/src/main/java/org/hibernate/validator/internal/metadata/core/MetaConstraint.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.hibernate.validator.internal.engine.ValueContext;
2727
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
2828
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
29-
import org.hibernate.validator.internal.util.ReflectionHelper;
3029

3130
/**
3231
* Instances of this class abstract the constraint type (class, method or field constraint) and give access to
@@ -94,21 +93,6 @@ protected final Type typeOfAnnotatedElement() {
9493
return location.typeOfAnnotatedElement();
9594
}
9695

97-
/**
98-
* @param o the object from which to retrieve the value.
99-
*
100-
* @return Returns the value for this constraint from the specified object. Depending on the type either the value itself
101-
* is returned of method or field access is used to access the value.
102-
*/
103-
public Object getValue(Object o) {
104-
if ( location.getMember() == null ) {
105-
return o;
106-
}
107-
else {
108-
return ReflectionHelper.getValue( location.getMember(), o );
109-
}
110-
}
111-
11296
@Override
11397
public boolean equals(Object o) {
11498
if ( this == o ) {

engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedField.java

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,10 @@
1616
*/
1717
package org.hibernate.validator.internal.metadata.raw;
1818

19-
import java.lang.reflect.Member;
20-
import java.security.AccessController;
21-
import java.security.PrivilegedAction;
2219
import java.util.Set;
2320

2421
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
2522
import org.hibernate.validator.internal.metadata.location.BeanConstraintLocation;
26-
import org.hibernate.validator.internal.util.privilegedactions.SetAccessibility;
2723

2824
/**
2925
* Represents a field of a Java type and all its associated meta-data relevant
@@ -48,41 +44,9 @@ public ConstrainedField(ConfigurationSource source,
4844
boolean isCascading) {
4945

5046
super( source, ConstrainedElementKind.FIELD, location, constraints, isCascading );
51-
52-
Member member = location.getMember();
53-
if ( member != null && isConstrained() ) {
54-
run( SetAccessibility.action( member ) );
55-
}
5647
}
5748

5849
public BeanConstraintLocation getLocation() {
5950
return (BeanConstraintLocation) super.getLocation();
6051
}
61-
62-
@Override
63-
public boolean equals(Object obj) {
64-
if ( this == obj ) {
65-
return true;
66-
}
67-
if ( !super.equals( obj ) ) {
68-
return false;
69-
}
70-
if ( getClass() != obj.getClass() ) {
71-
return false;
72-
}
73-
ConstrainedField other = (ConstrainedField) obj;
74-
if ( getLocation().getMember() == null ) {
75-
if ( other.getLocation().getMember() != null ) {
76-
return false;
77-
}
78-
}
79-
else if ( !getLocation().getMember().equals( other.getLocation().getMember() ) ) {
80-
return false;
81-
}
82-
return true;
83-
}
84-
85-
private <T> T run(PrivilegedAction<T> action) {
86-
return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
87-
}
8852
}

0 commit comments

Comments
 (0)