Skip to content

Commit caff03a

Browse files
committed
HV-1927 Use Executable#getAnnotatedParameterTypes() instead of Executable#getGenericParameterTypes()
getGenericParameterTypes() is problematic with synthetic and implicit parameters and we used to have ugly workarounds and warnings. Using getAnnotatedParameterTypes() solves the issue. I was extremely conservative in the changes as I want to be able to backport it.
1 parent 4a592ea commit caff03a

File tree

3 files changed

+20
-83
lines changed

3 files changed

+20
-83
lines changed

engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java

Lines changed: 4 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77
package org.hibernate.validator.internal.properties.javabean;
88

99
import java.lang.annotation.Annotation;
10-
import java.lang.invoke.MethodHandles;
1110
import java.lang.reflect.AnnotatedType;
1211
import java.lang.reflect.Executable;
1312
import java.lang.reflect.Method;
1413
import java.lang.reflect.Modifier;
1514
import java.lang.reflect.Parameter;
1615
import java.lang.reflect.Type;
17-
import java.lang.reflect.TypeVariable;
1816
import java.util.ArrayList;
1917
import java.util.Collections;
2018
import java.util.List;
@@ -25,18 +23,13 @@
2523
import org.hibernate.validator.internal.util.ExecutableHelper;
2624
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
2725
import org.hibernate.validator.internal.util.ReflectionHelper;
28-
import org.hibernate.validator.internal.util.TypeHelper;
29-
import org.hibernate.validator.internal.util.logging.Log;
30-
import org.hibernate.validator.internal.util.logging.LoggerFactory;
3126

3227
/**
3328
* @author Marko Bekhta
3429
* @author Guillaume Smet
3530
*/
3631
public abstract class JavaBeanExecutable<T extends Executable> implements Callable, JavaBeanAnnotatedConstrainable {
3732

38-
private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
39-
4033
protected final T executable;
4134
private final Type typeForValidatorResolution;
4235
private final boolean hasReturnValue;
@@ -194,72 +187,12 @@ private static List<JavaBeanParameter> getParameters(Executable executable) {
194187

195188
Parameter[] parameterArray = executable.getParameters();
196189
Class<?>[] parameterTypes = executable.getParameterTypes();
197-
// getGenericParameterTypes() does not include either the synthetic or the implicit parameters so we need to be
198-
// extra careful
199-
Type[] genericParameterTypes = executable.getGenericParameterTypes();
200-
201-
if ( parameterTypes.length == genericParameterTypes.length ) {
202-
// this is the simple case where both arrays are consistent
203-
// we could do without it but at some point, the behavior of getGenericParameterTypes() might be changed in
204-
// Java and we'd better be ready.
205-
for ( int i = 0; i < parameterArray.length; i++ ) {
206-
parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], getErasedTypeIfTypeVariable( genericParameterTypes[i] ) ) );
207-
}
208-
}
209-
else {
210-
// in this case, we have synthetic or implicit parameters
211-
212-
// do we have the information about which parameter is synthetic/implicit?
213-
// (this metadata is only included when classes are compiled with the '-parameters' flag)
214-
boolean hasParameterModifierInfo = isAnyParameterCarryingMetadata( parameterArray );
215-
216-
if ( ! hasParameterModifierInfo ) {
217-
LOG.missingParameterMetadataWithSyntheticOrImplicitParameters( executable );
218-
}
219-
220-
int explicitlyDeclaredParameterIndex = 0;
221-
222-
for ( int i = 0; i < parameterArray.length; i++ ) {
223-
if ( explicitlyDeclaredParameterIndex < genericParameterTypes.length // we might already be out of the bounds of generic params array
224-
&& isExplicit( parameterArray[i] )
225-
&& parameterTypesMatch( parameterTypes[i], genericParameterTypes[explicitlyDeclaredParameterIndex] ) ) {
226-
// in this case we have a parameter that is present and matches ("most likely") to the one in the generic parameter types list
227-
parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i],
228-
getErasedTypeIfTypeVariable( genericParameterTypes[explicitlyDeclaredParameterIndex] ) ) );
229-
explicitlyDeclaredParameterIndex++;
230-
}
231-
else {
232-
// in this case, the parameter is not present in genericParameterTypes, or the types doesn't match
233-
parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], parameterTypes[i] ) );
234-
}
235-
}
236-
}
237-
238-
return CollectionHelper.toImmutableList( parameters );
239-
}
240-
241-
private static boolean isAnyParameterCarryingMetadata(Parameter[] parameterArray) {
242-
for ( Parameter parameter : parameterArray ) {
243-
if ( parameter.isSynthetic() || parameter.isImplicit() ) {
244-
return true;
245-
}
246-
}
247-
return false;
248-
}
249-
250-
private static boolean parameterTypesMatch(Class<?> paramType, Type genericParamType) {
251-
return TypeHelper.getErasedType( genericParamType ).equals( paramType );
252-
}
190+
AnnotatedType[] annotatedTypes = executable.getAnnotatedParameterTypes();
253191

254-
private static boolean isExplicit(Parameter parameter) {
255-
return !parameter.isSynthetic() && !parameter.isImplicit();
256-
}
257-
258-
private static Type getErasedTypeIfTypeVariable(Type genericType) {
259-
if ( genericType instanceof TypeVariable ) {
260-
return TypeHelper.getErasedType( genericType );
192+
for ( int i = 0; i < parameterArray.length; i++ ) {
193+
parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], annotatedTypes[i] ) );
261194
}
262195

263-
return genericType;
196+
return CollectionHelper.toImmutableList( parameters );
264197
}
265198
}

engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.lang.reflect.Type;
1616
import java.lang.reflect.TypeVariable;
1717

18+
import org.hibernate.validator.internal.util.TypeHelper;
1819
import org.hibernate.validator.internal.util.logging.Log;
1920
import org.hibernate.validator.internal.util.logging.LoggerFactory;
2021

@@ -35,11 +36,14 @@ public class JavaBeanParameter implements JavaBeanAnnotatedElement {
3536

3637
private final Type genericType;
3738

38-
JavaBeanParameter(int index, Parameter parameter, Class<?> type, Type genericType) {
39+
private final AnnotatedType annotatedType;
40+
41+
JavaBeanParameter(int index, Parameter parameter, Class<?> type, AnnotatedType annotatedType) {
3942
this.index = index;
4043
this.parameter = parameter;
4144
this.type = type;
42-
this.genericType = genericType;
45+
this.genericType = getErasedTypeIfTypeVariable( annotatedType.getType() );
46+
this.annotatedType = annotatedType;
4347
}
4448

4549
public int getIndex() {
@@ -53,7 +57,7 @@ public Class<?> getType() {
5357

5458
@Override
5559
public AnnotatedType getAnnotatedType() {
56-
return parameter.getAnnotatedType();
60+
return annotatedType;
5761
}
5862

5963
@Override
@@ -75,11 +79,19 @@ public Type getGenericType() {
7579

7680
@Override
7781
public TypeVariable<?>[] getTypeParameters() {
78-
return parameter.getType().getTypeParameters();
82+
return type.getTypeParameters();
7983
}
8084

8185
@Override
8286
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
8387
return parameter.getAnnotation( annotationClass );
8488
}
89+
90+
private static Type getErasedTypeIfTypeVariable(Type genericType) {
91+
if ( genericType instanceof TypeVariable ) {
92+
return TypeHelper.getErasedType( genericType );
93+
}
94+
95+
return genericType;
96+
}
8597
}

engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -895,14 +895,6 @@ ConstraintDefinitionException getConstraintValidatorDefinitionConstraintMismatch
895895
@Message(id = 253, value = "Unable to instantiate property node name provider class %s.")
896896
ValidationException getUnableToInstantiatePropertyNodeNameProviderClassException(String propertyNodeNameProviderClassName, @Cause Exception e);
897897

898-
@LogMessage(level = WARN)
899-
@Message(id = 254, value = "Missing parameter metadata for %s, which declares implicit or synthetic parameters."
900-
+ " Automatic resolution of generic type information for method parameters"
901-
+ " may yield incorrect results if multiple parameters have the same erasure."
902-
+ " To solve this, compile your code with the '-parameters' flag."
903-
)
904-
void missingParameterMetadataWithSyntheticOrImplicitParameters(@FormatWith(ExecutableFormatter.class) Executable executable);
905-
906898
@LogMessage(level = DEBUG)
907899
@Message(id = 255, value = "Using %s as locale resolver.")
908900
void usingLocaleResolver(@FormatWith(ClassObjectFormatter.class) Class<? extends LocaleResolver> localeResolverClass);

0 commit comments

Comments
 (0)