87 88 /** 89 * Ensures that access to a member is granted and throws 90 * IllegalAccessException if not. 91 * 92 * @param currentClass the class performing the access 93 * @param memberClass the declaring class of the member being accessed 94 * @param targetClass the class of target object if accessing instance 95 * field or method; 96 * or the declaring class if accessing constructor; 97 * or null if accessing static field or method 98 * @param modifiers the member's access modifiers 99 * @throws IllegalAccessException if access to member is denied 100 */ 101 public static void ensureMemberAccess(Class<?> currentClass, 102 Class<?> memberClass, 103 Class<?> targetClass, 104 int modifiers) 105 throws IllegalAccessException 106 { 107 if (currentClass == null || memberClass == null) { 108 throw new InternalError(); 109 } 110 111 if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) { 112 throwIllegalAccessException(currentClass, memberClass, targetClass, modifiers); 113 } 114 } 115 116 /** 117 * Verify access to a member, returning {@code false} if no access 118 */ 119 public static boolean verifyMemberAccess(Class<?> currentClass, 120 Class<?> memberClass, 121 Class<?> targetClass, 122 int modifiers) 123 { 124 // Verify that currentClass can access a field, method, or 125 // constructor of memberClass, where that member's access bits are 126 // "modifiers". 127 128 boolean gotIsSameClassPackage = false; 129 boolean isSameClassPackage = false; 130 131 if (currentClass == memberClass) { 132 // Always succeeds 133 return true; 134 } 135 136 if (!verifyModuleAccess(currentClass, memberClass)) { 137 return false; 138 } 139 140 if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { 141 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 142 gotIsSameClassPackage = true; 143 if (!isSameClassPackage) { 144 return false; 145 } 146 } 147 148 // At this point we know that currentClass can access memberClass. 149 150 if (Modifier.isPublic(modifiers)) { 151 return true; 152 } 153 154 boolean successSoFar = false; 155 156 if (Modifier.isProtected(modifiers)) { 157 // See if currentClass is a subclass of memberClass 158 if (isSubclassOf(currentClass, memberClass)) { 159 successSoFar = true; 180 // and protected constructors: JLS 6.6.2 181 if (targetClass != null && Modifier.isProtected(modifiers) && 182 targetClass != currentClass) 183 { 184 if (!gotIsSameClassPackage) { 185 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 186 gotIsSameClassPackage = true; 187 } 188 if (!isSameClassPackage) { 189 if (!isSubclassOf(targetClass, currentClass)) { 190 return false; 191 } 192 } 193 } 194 195 return true; 196 } 197 198 /** 199 * Returns {@code true} if memberClass's's module exports memberClass's 200 * package to currentClass's module. 201 */ 202 public static boolean verifyModuleAccess(Class<?> currentClass, 203 Class<?> memberClass) { 204 return verifyModuleAccess(currentClass.getModule(), memberClass); 205 } 206 207 public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) { 208 Module memberModule = memberClass.getModule(); 209 210 // module may be null during startup (initLevel 0) 211 if (currentModule == memberModule) 212 return true; // same module (named or unnamed) 213 214 String pkg = memberClass.getPackageName(); 215 boolean allowed = memberModule.isExported(pkg, currentModule); 216 if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) { 217 if (!SharedSecrets.getJavaLangReflectModuleAccess() 218 .isStaticallyExported(memberModule, pkg, currentModule)) { 219 String msg = currentModule + " allowed access to member of " + memberClass; 220 new Exception(msg).printStackTrace(System.err); 221 } 222 } 223 return allowed; 224 } 225 226 /** 227 * Returns true if two classes in the same package. 228 */ 229 private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) { 230 if (c1.getClassLoader() != c2.getClassLoader()) 231 return false; 232 return Objects.equals(c1.getPackageName(), c2.getPackageName()); 361 if (s != null) { 362 printStackWhenAccessFails = !s.equalsIgnoreCase("false"); 363 printStackWhenAccessSucceeds = s.equalsIgnoreCase("access"); 364 } 365 printStackPropertiesSet = true; 366 } 367 } 368 369 public static boolean printStackTraceWhenAccessFails() { 370 ensurePrintStackPropertiesSet(); 371 return printStackWhenAccessFails; 372 } 373 374 public static boolean printStackTraceWhenAccessSucceeds() { 375 ensurePrintStackPropertiesSet(); 376 return printStackWhenAccessSucceeds; 377 } 378 379 /** 380 * Throws IllegalAccessException with the an exception message based on 381 * the access that is denied. 382 */ 383 private static void throwIllegalAccessException(Class<?> currentClass, 384 Class<?> memberClass, 385 Object target, 386 int modifiers) 387 throws IllegalAccessException 388 { 389 String currentSuffix = ""; 390 String memberSuffix = ""; 391 Module m1 = currentClass.getModule(); 392 if (m1.isNamed()) 393 currentSuffix = " (in " + m1 + ")"; 394 Module m2 = memberClass.getModule(); 395 if (m2.isNamed()) 396 memberSuffix = " (in " + m2 + ")"; 397 398 String memberPackageName = memberClass.getPackageName(); 399 400 String msg = currentClass + currentSuffix + " cannot access "; 401 if (m2.isExported(memberPackageName, m1)) { 402 403 // module access okay so include the modifiers in the message 404 msg += "a member of " + memberClass + memberSuffix + 405 " with modifiers \"" + Modifier.toString(modifiers) + "\""; | 87 88 /** 89 * Ensures that access to a member is granted and throws 90 * IllegalAccessException if not. 91 * 92 * @param currentClass the class performing the access 93 * @param memberClass the declaring class of the member being accessed 94 * @param targetClass the class of target object if accessing instance 95 * field or method; 96 * or the declaring class if accessing constructor; 97 * or null if accessing static field or method 98 * @param modifiers the member's access modifiers 99 * @throws IllegalAccessException if access to member is denied 100 */ 101 public static void ensureMemberAccess(Class<?> currentClass, 102 Class<?> memberClass, 103 Class<?> targetClass, 104 int modifiers) 105 throws IllegalAccessException 106 { 107 if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) { 108 throwIllegalAccessException(currentClass, memberClass, targetClass, modifiers); 109 } 110 } 111 112 /** 113 * Verify access to a member and return {@code true} if it is granted. 114 * 115 * @param currentClass the class performing the access 116 * @param memberClass the declaring class of the member being accessed 117 * @param targetClass the class of target object if accessing instance 118 * field or method; 119 * or the declaring class if accessing constructor; 120 * or null if accessing static field or method 121 * @param modifiers the member's access modifiers 122 * @return {@code true} if access to member is granted 123 */ 124 public static boolean verifyMemberAccess(Class<?> currentClass, 125 Class<?> memberClass, 126 Class<?> targetClass, 127 int modifiers) 128 { 129 Objects.requireNonNull(currentClass, "currentClass"); 130 Objects.requireNonNull(memberClass, "memberClass"); 131 132 if (currentClass == memberClass) { 133 // Always succeeds 134 return true; 135 } 136 137 if (!verifyModuleAccess(currentClass.getModule(), memberClass)) { 138 return false; 139 } 140 141 boolean gotIsSameClassPackage = false; 142 boolean isSameClassPackage = false; 143 144 if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { 145 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 146 gotIsSameClassPackage = true; 147 if (!isSameClassPackage) { 148 return false; 149 } 150 } 151 152 // At this point we know that currentClass can access memberClass. 153 154 if (Modifier.isPublic(modifiers)) { 155 return true; 156 } 157 158 boolean successSoFar = false; 159 160 if (Modifier.isProtected(modifiers)) { 161 // See if currentClass is a subclass of memberClass 162 if (isSubclassOf(currentClass, memberClass)) { 163 successSoFar = true; 184 // and protected constructors: JLS 6.6.2 185 if (targetClass != null && Modifier.isProtected(modifiers) && 186 targetClass != currentClass) 187 { 188 if (!gotIsSameClassPackage) { 189 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 190 gotIsSameClassPackage = true; 191 } 192 if (!isSameClassPackage) { 193 if (!isSubclassOf(targetClass, currentClass)) { 194 return false; 195 } 196 } 197 } 198 199 return true; 200 } 201 202 /** 203 * Returns {@code true} if memberClass's's module exports memberClass's 204 * package to currentModule. 205 */ 206 public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) { 207 if (VM.isModuleSystemInited()) 208 Objects.requireNonNull(currentModule, "currentModule"); 209 Objects.requireNonNull(memberClass, "memberClass"); 210 211 Module memberModule = memberClass.getModule(); 212 213 // module may be null during startup (initLevel < VM.MODULE_SYSTEM_INITED) 214 if (currentModule == memberModule) 215 return true; // same module (named or unnamed) or both are null 216 217 String pkg = memberClass.getPackageName(); 218 boolean allowed = memberModule.isExported(pkg, currentModule); 219 if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) { 220 if (!SharedSecrets.getJavaLangReflectModuleAccess() 221 .isStaticallyExported(memberModule, pkg, currentModule)) { 222 String msg = currentModule + " allowed access to member of " + memberClass; 223 new Exception(msg).printStackTrace(System.err); 224 } 225 } 226 return allowed; 227 } 228 229 /** 230 * Returns true if two classes in the same package. 231 */ 232 private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) { 233 if (c1.getClassLoader() != c2.getClassLoader()) 234 return false; 235 return Objects.equals(c1.getPackageName(), c2.getPackageName()); 364 if (s != null) { 365 printStackWhenAccessFails = !s.equalsIgnoreCase("false"); 366 printStackWhenAccessSucceeds = s.equalsIgnoreCase("access"); 367 } 368 printStackPropertiesSet = true; 369 } 370 } 371 372 public static boolean printStackTraceWhenAccessFails() { 373 ensurePrintStackPropertiesSet(); 374 return printStackWhenAccessFails; 375 } 376 377 public static boolean printStackTraceWhenAccessSucceeds() { 378 ensurePrintStackPropertiesSet(); 379 return printStackWhenAccessSucceeds; 380 } 381 382 /** 383 * Throws IllegalAccessException with the an exception message based on 384 * the access that is denied. This method throws meaningful exception only 385 * when {@link #verifyMemberAccess(Class, Class, Class, int)} returns false 386 * for the same parameters. 387 */ 388 public static void throwIllegalAccessException(Class<?> currentClass, 389 Class<?> memberClass, 390 Class<?> targetClass, 391 int modifiers) 392 throws IllegalAccessException 393 { 394 String currentSuffix = ""; 395 String memberSuffix = ""; 396 Module m1 = currentClass.getModule(); 397 if (m1.isNamed()) 398 currentSuffix = " (in " + m1 + ")"; 399 Module m2 = memberClass.getModule(); 400 if (m2.isNamed()) 401 memberSuffix = " (in " + m2 + ")"; 402 403 String memberPackageName = memberClass.getPackageName(); 404 405 String msg = currentClass + currentSuffix + " cannot access "; 406 if (m2.isExported(memberPackageName, m1)) { 407 408 // module access okay so include the modifiers in the message 409 msg += "a member of " + memberClass + memberSuffix + 410 " with modifiers \"" + Modifier.toString(modifiers) + "\""; |