From 58466edd97ff88c9401b49b9e3f9e85b763435d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 23 Feb 2023 14:00:16 +0100 Subject: [PATCH] HV-1939 Work around JDK-8303112 --- .../javabean/JavaBeanExecutable.java | 59 ++++++++++++++++++- .../javabean/JavaBeanParameter.java | 25 +++++++- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java index 73b31d02aa..db93028e06 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java @@ -14,6 +14,7 @@ import java.lang.reflect.Parameter; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -183,16 +184,70 @@ private static List getParameters(Executable executable) { return Collections.emptyList(); } - List parameters = new ArrayList<>( executable.getParameterCount() ); + int parameterCount = executable.getParameterCount(); + List parameters = new ArrayList<>( parameterCount ); Parameter[] parameterArray = executable.getParameters(); Class[] parameterTypes = executable.getParameterTypes(); AnnotatedType[] annotatedTypes = executable.getAnnotatedParameterTypes(); + Annotation[][] parameterAnnotationsArray = executable.getParameterAnnotations(); + Annotation[][] annotationsForJDK8303112 = + recomputeParameterAnnotationsForJDK8303112( parameterArray, parameterAnnotationsArray ); + for ( int i = 0; i < parameterArray.length; i++ ) { - parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], annotatedTypes[i] ) ); + parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], annotatedTypes[i], + annotationsForJDK8303112 != null ? annotationsForJDK8303112[i] : null ) ); } return CollectionHelper.toImmutableList( parameters ); } + + /** + * This is a workaround for JDK-8303112. + * @param parameters The result of calling {@link Executable#getParameters()} + * @param parameterAnnotationsArray The result of calling {@link Executable#getParameterAnnotations()} + * @return A fixed version of {@code parameterAnnotationsArray}, + * or {@code null} if {@code parameterAnnotationsArray} is fine an unaffected by JDK-8303112. + */ + private static Annotation[][] recomputeParameterAnnotationsForJDK8303112(Parameter[] parameters, + Annotation[][] parameterAnnotationsArray) { + int parameterCount = parameters.length; + if ( parameterAnnotationsArray.length == parameterCount ) { + // Not affected by JDK-8303112 + return null; + } + + // We're in a situation where parameter.getAnnotation()/parameter.getAnnotations() + // is buggy when there are implicit/synthetic parameters, + // because constructor.getParameterAnnotations() (wrongly) ignores implicit/synthetic parameters + // while parameter.getAnnotations() (rightly) assumes they are present in the array. + + Annotation[][] annotationsForJDK8303112; + annotationsForJDK8303112 = new Annotation[parameterCount][]; + int nonImplicitNorSyntheticParamIndex = 0; + for ( int i = 0; i < parameterCount; i++ ) { + Parameter parameter = parameters[i]; + if ( parameter.isImplicit() || parameter.isSynthetic() ) { + annotationsForJDK8303112[i] = new Annotation[0]; + } + else if ( nonImplicitNorSyntheticParamIndex < parameterAnnotationsArray.length ) { + annotationsForJDK8303112[i] = + parameterAnnotationsArray[nonImplicitNorSyntheticParamIndex]; + ++nonImplicitNorSyntheticParamIndex; + } + else { + // Something is wrong; most likely the class wasn't compiled with -parameters + // and so isImplicit/isSynthetic always return false. + // As a last resort, assume the implicit/synthetic parameters are the first ones. + nonImplicitNorSyntheticParamIndex = parameterCount - parameterAnnotationsArray.length; + Arrays.fill( annotationsForJDK8303112, 0, nonImplicitNorSyntheticParamIndex, + new Annotation[0] ); + System.arraycopy( parameterAnnotationsArray, 0, annotationsForJDK8303112, + nonImplicitNorSyntheticParamIndex, parameterAnnotationsArray.length ); + return annotationsForJDK8303112; + } + } + return annotationsForJDK8303112; + } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java index a775591756..67c8002f43 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java @@ -26,7 +26,7 @@ public class JavaBeanParameter implements JavaBeanAnnotatedElement { private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() ); - private static final Annotation[] EMPTY_PARAMETER_ANNOTATIONS = new Annotation[0]; + static final Annotation[] EMPTY_PARAMETER_ANNOTATIONS = new Annotation[0]; private final int index; @@ -38,12 +38,16 @@ public class JavaBeanParameter implements JavaBeanAnnotatedElement { private final AnnotatedType annotatedType; - JavaBeanParameter(int index, Parameter parameter, Class type, AnnotatedType annotatedType) { + private final Annotation[] annotationsForJDK8303112; + + JavaBeanParameter(int index, Parameter parameter, Class type, AnnotatedType annotatedType, + Annotation[] annotationsForJDK8303112) { this.index = index; this.parameter = parameter; this.type = type; this.genericType = getErasedTypeIfTypeVariable( annotatedType.getType() ); this.annotatedType = annotatedType; + this.annotationsForJDK8303112 = annotationsForJDK8303112; } public int getIndex() { @@ -63,10 +67,14 @@ public AnnotatedType getAnnotatedType() { @Override public Annotation[] getDeclaredAnnotations() { try { + if ( annotationsForJDK8303112 != null ) { + // Working around https://bugs.openjdk.org/browse/JDK-8303112 + return annotationsForJDK8303112.clone(); + } return parameter.getDeclaredAnnotations(); } catch (ArrayIndexOutOfBoundsException ex) { - // This looks like a JVM bug we are trying to work around, kept as is for now + // This looks like our workaround failed... assume there were no annotations and hope for the best. LOG.warn( MESSAGES.constraintOnConstructorOfNonStaticInnerClass(), ex ); return EMPTY_PARAMETER_ANNOTATIONS; } @@ -84,6 +92,17 @@ public TypeVariable[] getTypeParameters() { @Override public A getAnnotation(Class annotationClass) { + if ( annotationsForJDK8303112 != null ) { + // Working around https://bugs.openjdk.org/browse/JDK-8303112 + for ( Annotation annotation : annotationsForJDK8303112 ) { + if ( annotationClass.isAssignableFrom( annotation.annotationType() ) ) { + @SuppressWarnings("unchecked") + A castAnnotation = (A) annotation; + return castAnnotation; + } + } + return null; + } return parameter.getAnnotation( annotationClass ); }