Path: blob/master/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
41159 views
/*1* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package jdk.internal.reflect;2627import java.lang.reflect.*;28import java.util.HashMap;29import java.util.Map;30import java.util.Objects;31import java.util.Set;32import jdk.internal.access.SharedSecrets;33import jdk.internal.misc.VM;34import jdk.internal.vm.annotation.IntrinsicCandidate;3536/** Common utility routines used by both java.lang and37java.lang.reflect */3839public class Reflection {4041/** Used to filter out fields and methods from certain classes from public42view, where they are sensitive or they may contain VM-internal objects.43These Maps are updated very rarely. Rather than synchronize on44each access, we use copy-on-write */45private static volatile Map<Class<?>, Set<String>> fieldFilterMap;46private static volatile Map<Class<?>, Set<String>> methodFilterMap;47private static final String WILDCARD = "*";48public static final Set<String> ALL_MEMBERS = Set.of(WILDCARD);4950static {51fieldFilterMap = Map.of(52Reflection.class, ALL_MEMBERS,53AccessibleObject.class, ALL_MEMBERS,54Class.class, Set.of("classLoader", "classData"),55ClassLoader.class, ALL_MEMBERS,56Constructor.class, ALL_MEMBERS,57Field.class, ALL_MEMBERS,58Method.class, ALL_MEMBERS,59Module.class, ALL_MEMBERS,60System.class, Set.of("security")61);62methodFilterMap = Map.of();63}6465/** Returns the class of the caller of the method calling this method,66ignoring frames associated with java.lang.reflect.Method.invoke()67and its implementation. */68@CallerSensitive69@IntrinsicCandidate70public static native Class<?> getCallerClass();7172/** Retrieves the access flags written to the class file. For73inner classes these flags may differ from those returned by74Class.getModifiers(), which searches the InnerClasses75attribute to find the source-level access flags. This is used76instead of Class.getModifiers() for run-time access checks due77to compatibility reasons; see 4471811. Only the values of the78low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be79valid. */80@IntrinsicCandidate81public static native int getClassAccessFlags(Class<?> c);828384/**85* Ensures that access to a member is granted and throws86* IllegalAccessException if not.87*88* @param currentClass the class performing the access89* @param memberClass the declaring class of the member being accessed90* @param targetClass the class of target object if accessing instance91* field or method;92* or the declaring class if accessing constructor;93* or null if accessing static field or method94* @param modifiers the member's access modifiers95* @throws IllegalAccessException if access to member is denied96*/97public static void ensureMemberAccess(Class<?> currentClass,98Class<?> memberClass,99Class<?> targetClass,100int modifiers)101throws IllegalAccessException102{103if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) {104throw newIllegalAccessException(currentClass, memberClass, targetClass, modifiers);105}106}107108public static void ensureNativeAccess(Class<?> currentClass) {109Module module = currentClass.getModule();110if (!SharedSecrets.getJavaLangAccess().isEnableNativeAccess(module)) {111throw new IllegalCallerException("Illegal native access from: " + module);112}113}114115/**116* Verify access to a member and return {@code true} if it is granted.117*118* @param currentClass the class performing the access119* @param memberClass the declaring class of the member being accessed120* @param targetClass the class of target object if accessing instance121* field or method;122* or the declaring class if accessing constructor;123* or null if accessing static field or method124* @param modifiers the member's access modifiers125* @return {@code true} if access to member is granted126*/127public static boolean verifyMemberAccess(Class<?> currentClass,128Class<?> memberClass,129Class<?> targetClass,130int modifiers)131{132Objects.requireNonNull(currentClass);133Objects.requireNonNull(memberClass);134135if (currentClass == memberClass) {136// Always succeeds137return true;138}139140if (!verifyModuleAccess(currentClass.getModule(), memberClass)) {141return false;142}143144boolean gotIsSameClassPackage = false;145boolean isSameClassPackage = false;146147if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {148isSameClassPackage = isSameClassPackage(currentClass, memberClass);149gotIsSameClassPackage = true;150if (!isSameClassPackage) {151return false;152}153}154155// At this point we know that currentClass can access memberClass.156157if (Modifier.isPublic(modifiers)) {158return true;159}160161// Check for nestmate access if member is private162if (Modifier.isPrivate(modifiers)) {163// Note: targetClass may be outside the nest, but that is okay164// as long as memberClass is in the nest.165if (areNestMates(currentClass, memberClass)) {166return true;167}168}169170boolean successSoFar = false;171172if (Modifier.isProtected(modifiers)) {173// See if currentClass is a subclass of memberClass174if (isSubclassOf(currentClass, memberClass)) {175successSoFar = true;176}177}178179if (!successSoFar && !Modifier.isPrivate(modifiers)) {180if (!gotIsSameClassPackage) {181isSameClassPackage = isSameClassPackage(currentClass,182memberClass);183gotIsSameClassPackage = true;184}185186if (isSameClassPackage) {187successSoFar = true;188}189}190191if (!successSoFar) {192return false;193}194195// Additional test for protected instance members196// and protected constructors: JLS 6.6.2197if (targetClass != null && Modifier.isProtected(modifiers) &&198targetClass != currentClass)199{200if (!gotIsSameClassPackage) {201isSameClassPackage = isSameClassPackage(currentClass, memberClass);202gotIsSameClassPackage = true;203}204if (!isSameClassPackage) {205if (!isSubclassOf(targetClass, currentClass)) {206return false;207}208}209}210211return true;212}213214/*215* Verify if a member is public and memberClass is a public type216* in a package that is unconditionally exported and217* return {@code true} if it is granted.218*219* @param memberClass the declaring class of the member being accessed220* @param modifiers the member's access modifiers221* @return {@code true} if the member is public and in a publicly accessible type222*/223public static boolean verifyPublicMemberAccess(Class<?> memberClass, int modifiers) {224Module m = memberClass.getModule();225return Modifier.isPublic(modifiers)226&& m.isExported(memberClass.getPackageName())227&& Modifier.isPublic(Reflection.getClassAccessFlags(memberClass));228}229230/**231* Returns {@code true} if memberClass's module exports memberClass's232* package to currentModule.233*/234public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) {235Module memberModule = memberClass.getModule();236if (currentModule == memberModule) {237// same module (named or unnamed) or both null if called238// before module system is initialized, which means we are239// dealing with java.base only.240return true;241} else {242String pkg = memberClass.getPackageName();243return memberModule.isExported(pkg, currentModule);244}245}246247/**248* Returns true if two classes in the same package.249*/250private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {251if (c1.getClassLoader() != c2.getClassLoader())252return false;253return Objects.equals(c1.getPackageName(), c2.getPackageName());254}255256static boolean isSubclassOf(Class<?> queryClass,257Class<?> ofClass)258{259while (queryClass != null) {260if (queryClass == ofClass) {261return true;262}263queryClass = queryClass.getSuperclass();264}265return false;266}267268// fieldNames must contain only interned Strings269public static synchronized void registerFieldsToFilter(Class<?> containingClass,270Set<String> fieldNames) {271fieldFilterMap =272registerFilter(fieldFilterMap, containingClass, fieldNames);273}274275// methodNames must contain only interned Strings276public static synchronized void registerMethodsToFilter(Class<?> containingClass,277Set<String> methodNames) {278methodFilterMap =279registerFilter(methodFilterMap, containingClass, methodNames);280}281282private static Map<Class<?>, Set<String>> registerFilter(Map<Class<?>, Set<String>> map,283Class<?> containingClass,284Set<String> names) {285if (map.get(containingClass) != null) {286throw new IllegalArgumentException287("Filter already registered: " + containingClass);288}289map = new HashMap<>(map);290map.put(containingClass, Set.copyOf(names));291return map;292}293294public static Field[] filterFields(Class<?> containingClass, Field[] fields) {295if (fieldFilterMap == null) {296// Bootstrapping297return fields;298}299return (Field[])filter(fields, fieldFilterMap.get(containingClass));300}301302public static Method[] filterMethods(Class<?> containingClass, Method[] methods) {303if (methodFilterMap == null) {304// Bootstrapping305return methods;306}307return (Method[])filter(methods, methodFilterMap.get(containingClass));308}309310private static Member[] filter(Member[] members, Set<String> filteredNames) {311if ((filteredNames == null) || (members.length == 0)) {312return members;313}314Class<?> memberType = members[0].getClass();315if (filteredNames.contains(WILDCARD)) {316return (Member[]) Array.newInstance(memberType, 0);317}318int numNewMembers = 0;319for (Member member : members) {320if (!filteredNames.contains(member.getName())) {321++numNewMembers;322}323}324Member[] newMembers = (Member[])Array.newInstance(memberType, numNewMembers);325int destIdx = 0;326for (Member member : members) {327if (!filteredNames.contains(member.getName())) {328newMembers[destIdx++] = member;329}330}331return newMembers;332}333334/**335* Tests if the given method is caller-sensitive and the declaring class336* is defined by either the bootstrap class loader or platform class loader.337*/338public static boolean isCallerSensitive(Method m) {339final ClassLoader loader = m.getDeclaringClass().getClassLoader();340if (VM.isSystemDomainLoader(loader)) {341return m.isAnnotationPresent(CallerSensitive.class);342}343return false;344}345346/*347* Tests if the given Field is a trusted final field and it cannot be348* modified reflectively regardless of the value of its accessible flag.349*/350public static boolean isTrustedFinalField(Field field) {351return SharedSecrets.getJavaLangReflectAccess().isTrustedFinalField(field);352}353354/**355* Returns an IllegalAccessException with an exception message based on356* the access that is denied.357*/358public static IllegalAccessException newIllegalAccessException(Class<?> currentClass,359Class<?> memberClass,360Class<?> targetClass,361int modifiers)362{363if (currentClass == null)364return newIllegalAccessException(memberClass, modifiers);365366String currentSuffix = "";367String memberSuffix = "";368Module m1 = currentClass.getModule();369if (m1.isNamed())370currentSuffix = " (in " + m1 + ")";371Module m2 = memberClass.getModule();372if (m2.isNamed())373memberSuffix = " (in " + m2 + ")";374375String memberPackageName = memberClass.getPackageName();376377String msg = currentClass + currentSuffix + " cannot access ";378if (m2.isExported(memberPackageName, m1)) {379380// module access okay so include the modifiers in the message381msg += "a member of " + memberClass + memberSuffix +382" with modifiers \"" + Modifier.toString(modifiers) + "\"";383384} else {385// module access failed386msg += memberClass + memberSuffix+ " because "387+ m2 + " does not export " + memberPackageName;388if (m2.isNamed()) msg += " to " + m1;389}390391return new IllegalAccessException(msg);392}393394/**395* Returns an IllegalAccessException with an exception message where396* there is no caller frame.397*/398private static IllegalAccessException newIllegalAccessException(Class<?> memberClass,399int modifiers)400{401String memberSuffix = "";402Module m2 = memberClass.getModule();403if (m2.isNamed())404memberSuffix = " (in " + m2 + ")";405406String memberPackageName = memberClass.getPackageName();407408String msg = "JNI attached native thread (null caller frame) cannot access ";409if (m2.isExported(memberPackageName)) {410411// module access okay so include the modifiers in the message412msg += "a member of " + memberClass + memberSuffix +413" with modifiers \"" + Modifier.toString(modifiers) + "\"";414415} else {416// module access failed417msg += memberClass + memberSuffix+ " because "418+ m2 + " does not export " + memberPackageName;419}420421return new IllegalAccessException(msg);422}423424/**425* Returns true if {@code currentClass} and {@code memberClass}426* are nestmates - that is, if they have the same nesthost as427* determined by the VM.428*/429public static native boolean areNestMates(Class<?> currentClass,430Class<?> memberClass);431}432433434