From 83d326748599a7d5fb2316cda4eb193d2e5551d6 Mon Sep 17 00:00:00 2001 From: Jason Feng Date: Fri, 1 Dec 2023 10:18:03 -0500 Subject: [PATCH] JDK22+ adds JavaLangAccess.findMethod(isPublic, methodName, parameters) getMethodHelper() is updated to take the method type to be searched. Signed-off-by: Jason Feng --- .../share/classes/java/lang/Access.java | 6 ++ .../share/classes/java/lang/Class.java | 85 ++++++++++++++++--- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/jcl/src/java.base/share/classes/java/lang/Access.java b/jcl/src/java.base/share/classes/java/lang/Access.java index d9f31f29004..67fe4b58942 100644 --- a/jcl/src/java.base/share/classes/java/lang/Access.java +++ b/jcl/src/java.base/share/classes/java/lang/Access.java @@ -750,6 +750,12 @@ public boolean bytesCompatible(String string, Charset charset) { public void copyToSegmentRaw(String string, MemorySegment segment, long offset) { string.copyToSegmentRaw(segment, offset); } + + // No @Override to avoid breaking valhalla builds which is behind latest OpenJDK head stream update. + public Method findMethod(Class clazz, boolean isPublic, String methodName, Class... parameterTypes) { + return clazz.findMethod(isPublic, methodName, parameterTypes); + } + /*[ENDIF] JAVA_SPEC_VERSION >= 22 */ /*[IF INLINE-TYPES]*/ diff --git a/jcl/src/java.base/share/classes/java/lang/Class.java b/jcl/src/java.base/share/classes/java/lang/Class.java index 534725ec7ca..42c9f49d853 100644 --- a/jcl/src/java.base/share/classes/java/lang/Class.java +++ b/jcl/src/java.base/share/classes/java/lang/Class.java @@ -255,6 +255,18 @@ private static final class AnnotationCache { private static boolean reflectCacheDebug; private static boolean reflectCacheAppOnly = true; + /* + * The target method types to be searched by getMethodHelper(). + */ + enum SearchMethodType { + // all method types, public or not + ALL, + // public method only + PUBLIC, + // not public method + NOTPUBLIC, + } + /* * This {@code ClassReflectNullPlaceHolder} class is created to indicate the cached class value is * initialized to null rather than the default value null ;e.g. {@code cachedDeclaringClass} @@ -1700,11 +1712,22 @@ private Method throwExceptionOrReturnNull(boolean throwException, String name, C return null; } } + +/** + * A convenient method for getMethodHelper() with SearchMethodType.ALL. + */ +Method getMethodHelper( + boolean throwException, boolean forDeclaredMethod, List methodList, String name, Class... parameterTypes) + throws NoSuchMethodException { + return getMethodHelper(throwException, forDeclaredMethod, methodList, SearchMethodType.ALL, name, parameterTypes); +} + /** * Helper method for * public Method getDeclaredMethod(String name, Class... parameterTypes) * public Method getMethod(String name, Class... parameterTypes) * List getDeclaredPublicMethods(String name, Class... parameterTypes) + * Method findMethod(boolean isPublic, String methodName, Class... parameterTypes) * without going thorough security checking * * @param throwException boolean @@ -1713,24 +1736,30 @@ private Method throwExceptionOrReturnNull(boolean throwException, String name, C * @param forDeclaredMethod boolean * true - for getDeclaredMethod(String name, Class... parameterTypes) * & getDeclaredPublicMethods(String name, Class... parameterTypes); - * false - for getMethod(String name, Class... parameterTypes); + * false - for getMethod(String name, Class... parameterTypes) + * & findMethod(boolean isPublic, String methodName, Class... parameterTypes); * @param name String the name of the method * @param parameterTypes Class[] the types of the arguments * @param methodList List a list to store the methods described by the arguments * for getDeclaredPublicMethods() - * or null for getDeclaredMethod() & getMethod() + * or null for getDeclaredMethod(), getMethod() & findMethod() + * @param methodScope SearchMethodType the method type to be searched + * SearchMethodType.PUBLIC/NOTPUBLIC for findMethod() + * or SearchMethodType.ALL for others * @return Method the method described by the arguments. * @throws NoSuchMethodException if the method could not be found. */ @CallerSensitive Method getMethodHelper( - boolean throwException, boolean forDeclaredMethod, List methodList, String name, Class... parameterTypes) + boolean throwException, boolean forDeclaredMethod, List methodList, SearchMethodType searchMethodType, String name, Class... parameterTypes) throws NoSuchMethodException { Method result; Method bestCandidate; String strSig; boolean candidateFromInterface = false; - + boolean searchAllMethods = searchMethodType == SearchMethodType.ALL; + boolean searchPublicMethodOnly = searchMethodType == SearchMethodType.PUBLIC; + /*[PR CMVC 114820, CMVC 115873, CMVC 116166] add reflection cache */ if (parameterTypes == null) { parameterTypes = EmptyParameters; @@ -1738,10 +1767,19 @@ Method getMethodHelper( if (methodList == null) { // getDeclaredPublicMethods() has to go through all methods anyway Method cachedMethod = lookupCachedMethod(name, parameterTypes); - if ((cachedMethod != null) - && ((forDeclaredMethod && (cachedMethod.getDeclaringClass() == this)) - || (!forDeclaredMethod && Modifier.isPublic(cachedMethod.getModifiers())))) { - return cachedMethod; + if (cachedMethod != null) { + if (searchAllMethods && forDeclaredMethod && (cachedMethod.getDeclaringClass() == this)) { + return cachedMethod; + } else { + boolean isPublic = Modifier.isPublic(cachedMethod.getModifiers()); + if (searchAllMethods) { + if (!forDeclaredMethod && isPublic) { + return cachedMethod; + } + } else if (searchPublicMethodOnly == isPublic) { + return cachedMethod; + } + } } } @@ -1782,7 +1820,7 @@ Method getMethodHelper( } } } - + if (result == null) { return throwExceptionOrReturnNull(throwException, name, parameterTypes); } @@ -1807,7 +1845,8 @@ Method getMethodHelper( } } } - if ((methodList != null) && ((result.getModifiers() & Modifier.PUBLIC) != 0)) { + boolean publicMethodInitialResult = Modifier.isPublic(result.getModifiers()); + if ((methodList != null) && publicMethodInitialResult) { methodList.add(result); } @@ -1824,6 +1863,7 @@ Method getMethodHelper( * Otherwise, the result method is chosen arbitrarily from specific methods. */ bestCandidate = result; + boolean initialResultShouldBeReplaced = !searchAllMethods && (publicMethodInitialResult != searchPublicMethodOnly); if (!candidateFromInterface) { Class declaringClass = forDeclaredMethod ? this : result.getDeclaringClass(); while (true) { @@ -1831,11 +1871,16 @@ Method getMethodHelper( if (result == null) { break; } - boolean publicMethod = ((result.getModifiers() & Modifier.PUBLIC) != 0); + boolean publicMethod = Modifier.isPublic(result.getModifiers()); if ((methodList != null) && publicMethod) { methodList.add(result); } - if (forDeclaredMethod || publicMethod) { + boolean searchIsPublic = !searchAllMethods && (searchPublicMethodOnly == publicMethod); + if (searchIsPublic && initialResultShouldBeReplaced) { + // Current result is the method type to be found but the initial result wasn't. + bestCandidate = result; + initialResultShouldBeReplaced = false; + } else if (forDeclaredMethod || publicMethod || searchIsPublic) { // bestCandidate and result have same declaringClass. Class candidateRetType = bestCandidate.getReturnType(); Class resultRetType = result.getReturnType(); @@ -1845,7 +1890,12 @@ Method getMethodHelper( } } } - return cacheMethod(bestCandidate); + if (!searchAllMethods && initialResultShouldBeReplaced) { + // The initial result doesn't match the searching method type. + return null; + } else { + return cacheMethod(bestCandidate); + } } /** @@ -5819,5 +5869,14 @@ public static Class forPrimitiveName(String typeName) { default -> null; }; } + + Method findMethod(boolean isPublic, String methodName, Class... parameterTypes) { + try { + return getMethodHelper(true, false, null, isPublic ? SearchMethodType.PUBLIC : SearchMethodType.NOTPUBLIC, + methodName, parameterTypes); + } catch (NoSuchMethodException nsme) { + return null; + } + } /*[ENDIF] JAVA_SPEC_VERSION >= 22 */ }