|
17 | 17 | import java.util.stream.Collectors;
|
18 | 18 | import java.util.stream.Stream;
|
19 | 19 |
|
| 20 | +import org.hibernate.validator.internal.util.classhierarchy.Filters; |
20 | 21 | import org.hibernate.validator.internal.util.logging.Log;
|
21 | 22 | import org.hibernate.validator.internal.util.logging.LoggerFactory;
|
22 | 23 | import org.hibernate.validator.internal.util.privilegedactions.GetResolvedMemberMethods;
|
@@ -90,14 +91,83 @@ public boolean overrides(Method subTypeMethod, Method superTypeMethod) {
|
90 | 91 | return false;
|
91 | 92 | }
|
92 | 93 |
|
93 |
| - if ( !Modifier.isPublic( superTypeMethod.getModifiers() ) && !Modifier.isProtected( superTypeMethod.getModifiers() ) |
94 |
| - && !superTypeMethod.getDeclaringClass().getPackage().equals( subTypeMethod.getDeclaringClass().getPackage() ) ) { |
| 94 | + if ( !isOneMethodVisibleToAnother( subTypeMethod, superTypeMethod ) ) { |
95 | 95 | return false;
|
96 | 96 | }
|
97 | 97 |
|
98 | 98 | return instanceMethodParametersResolveToSameTypes( subTypeMethod, superTypeMethod );
|
99 | 99 | }
|
100 | 100 |
|
| 101 | + /** |
| 102 | + * Checks if a pair of given methods ({@code left} and {@code right}) are resolved to the same |
| 103 | + * method based on the {@code mainSubType} type. |
| 104 | + * |
| 105 | + * @param mainSubType a type at the bottom of class hierarchy to be used to lookup the methods. |
| 106 | + * @param left one of the methods to check |
| 107 | + * @param right another of the methods to check |
| 108 | + * |
| 109 | + * @return {@code true} if a pair of methods are equal {@code left == right}, or one of the methods |
| 110 | + * override another one in the class hierarchy with {@code mainSubType} at the bottom, |
| 111 | + * {@code false} otherwise. |
| 112 | + */ |
| 113 | + public boolean resolveToSameMethodInHierarchy(Class<?> mainSubType, Method left, Method right) { |
| 114 | + Contracts.assertValueNotNull( mainSubType, "mainSubType" ); |
| 115 | + Contracts.assertValueNotNull( left, "left" ); |
| 116 | + Contracts.assertValueNotNull( right, "right" ); |
| 117 | + |
| 118 | + if ( left.equals( right ) ) { |
| 119 | + return true; |
| 120 | + } |
| 121 | + |
| 122 | + if ( !left.getName().equals( right.getName() ) ) { |
| 123 | + return false; |
| 124 | + } |
| 125 | + |
| 126 | + // methods with same name in the same class should be different |
| 127 | + if ( left.getDeclaringClass().equals( right.getDeclaringClass() ) ) { |
| 128 | + return false; |
| 129 | + } |
| 130 | + |
| 131 | + if ( left.getParameterTypes().length != right.getParameterTypes().length ) { |
| 132 | + return false; |
| 133 | + } |
| 134 | + |
| 135 | + // if at least one method from a pair is static - they are different methods |
| 136 | + if ( Modifier.isStatic( right.getModifiers() ) || Modifier.isStatic( left.getModifiers() ) ) { |
| 137 | + return false; |
| 138 | + } |
| 139 | + |
| 140 | + // HV-861 Bridge method should be ignored. Classmates type/member resolution will take care of proper |
| 141 | + // override detection without considering bridge methods |
| 142 | + if ( left.isBridge() || right.isBridge() ) { |
| 143 | + return false; |
| 144 | + } |
| 145 | + |
| 146 | + // if one of the methods is private - methods are different |
| 147 | + if ( Modifier.isPrivate( left.getModifiers() ) || Modifier.isPrivate( right.getModifiers() ) ) { |
| 148 | + return false; |
| 149 | + } |
| 150 | + |
| 151 | + if ( !isOneMethodVisibleToAnother( left, right ) || !isOneMethodVisibleToAnother( right, left ) ) { |
| 152 | + return false; |
| 153 | + } |
| 154 | + |
| 155 | + // We need to check if the passed mainSubType is not a Weld proxy. In case of proxy we need to get |
| 156 | + // a class that was proxied otherwise we can use the class itself. This is due to the issue that |
| 157 | + // call to Class#getGenericInterfaces() on a Weld proxy returns raw types instead of parametrized |
| 158 | + // generics and methods will not be resolved correctly. |
| 159 | + return instanceMethodParametersResolveToSameTypes( |
| 160 | + Filters.excludeProxies().accepts( mainSubType ) ? mainSubType : mainSubType.getSuperclass(), |
| 161 | + left, |
| 162 | + right |
| 163 | + ); |
| 164 | + } |
| 165 | + |
| 166 | + private static boolean isOneMethodVisibleToAnother(Method left, Method right) { |
| 167 | + return Modifier.isPublic( right.getModifiers() ) || Modifier.isProtected( right.getModifiers() ) |
| 168 | + || right.getDeclaringClass().getPackage().equals( left.getDeclaringClass().getPackage() ); |
| 169 | + } |
| 170 | + |
101 | 171 | public static String getSimpleName(Executable executable) {
|
102 | 172 | return executable instanceof Constructor ? executable.getDeclaringClass().getSimpleName() : executable.getName();
|
103 | 173 | }
|
@@ -140,14 +210,18 @@ public static ElementType getElementType(Executable executable) {
|
140 | 210 | * @return {@code true} if the parameters of the two methods resolve to the same types, {@code false otherwise}.
|
141 | 211 | */
|
142 | 212 | private boolean instanceMethodParametersResolveToSameTypes(Method subTypeMethod, Method superTypeMethod) {
|
143 |
| - if ( subTypeMethod.getParameterTypes().length == 0 ) { |
| 213 | + return instanceMethodParametersResolveToSameTypes( subTypeMethod.getDeclaringClass(), subTypeMethod, superTypeMethod ); |
| 214 | + } |
| 215 | + |
| 216 | + private boolean instanceMethodParametersResolveToSameTypes(Class<?> mainSubType, Method left, Method right) { |
| 217 | + if ( left.getParameterTypes().length == 0 ) { |
144 | 218 | return true;
|
145 | 219 | }
|
146 | 220 |
|
147 |
| - ResolvedType resolvedSubType = typeResolver.resolve( subTypeMethod.getDeclaringClass() ); |
| 221 | + ResolvedType resolvedSubType = typeResolver.resolve( mainSubType ); |
148 | 222 |
|
149 | 223 | MemberResolver memberResolver = new MemberResolver( typeResolver );
|
150 |
| - memberResolver.setMethodFilter( new SimpleMethodFilter( subTypeMethod, superTypeMethod ) ); |
| 224 | + memberResolver.setMethodFilter( new SimpleMethodFilter( left, right ) ); |
151 | 225 | ResolvedTypeWithMembers typeWithMembers = memberResolver.resolve(
|
152 | 226 | resolvedSubType,
|
153 | 227 | null,
|
@@ -181,9 +255,9 @@ private boolean instanceMethodParametersResolveToSameTypes(Method subTypeMethod,
|
181 | 255 | catch (ArrayIndexOutOfBoundsException e) {
|
182 | 256 | LOG.debug(
|
183 | 257 | "Error in ExecutableHelper#instanceMethodParametersResolveToSameTypes comparing "
|
184 |
| - + subTypeMethod |
| 258 | + + left |
185 | 259 | + " with "
|
186 |
| - + superTypeMethod |
| 260 | + + right |
187 | 261 | );
|
188 | 262 | }
|
189 | 263 |
|
|
0 commit comments