1 /* 2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.reflect; 27 28 import java.lang.annotation.Annotation; 29 import java.lang.invoke.MethodHandle; 30 import java.security.AccessController; 31 32 import jdk.internal.misc.VM; 33 import jdk.internal.module.IllegalAccessLogger; 34 import jdk.internal.reflect.CallerSensitive; 35 import jdk.internal.reflect.Reflection; 36 import jdk.internal.reflect.ReflectionFactory; 37 import sun.security.action.GetPropertyAction; 38 39 /** 40 * The {@code AccessibleObject} class is the base class for {@code Field}, 41 * {@code Method}, and {@code Constructor} objects (known as <em>reflected 42 * objects</em>). It provides the ability to flag a reflected object as 43 * suppressing checks for Java language access control when it is used. This 44 * permits sophisticated applications with sufficient privilege, such as Java 45 * Object Serialization or other persistence mechanisms, to manipulate objects 46 * in a manner that would normally be prohibited. 47 * 48 * <p> Java language access control prevents use of private members outside 49 * their class; package access members outside their package; protected members 50 * outside their package or subclasses; and public members outside their 51 * module unless they are declared in an {@link Module#isExported(String,Module) 52 * exported} package and the user {@link Module#canRead reads} their module. By 53 * default, Java language access control is enforced (with one variation) when 54 * {@code Field}s, {@code Method}s, or {@code Constructor}s are used to get or 55 * set fields, to invoke methods, or to create and initialize new instances of 56 * classes, respectively. Every reflected object checks that the code using it 57 * is in an appropriate class, package, or module. </p> 58 * 59 * <p> The one variation from Java language access control is that the checks 60 * by reflected objects assume readability. That is, the module containing 61 * the use of a reflected object is assumed to read the module in which 62 * the underlying field, method, or constructor is declared. </p> 63 * 64 * <p> Whether the checks for Java language access control can be suppressed 65 * (and thus, whether access can be enabled) depends on whether the reflected 66 * object corresponds to a member in an exported or open package 67 * (see {@link #setAccessible(boolean)}). </p> 68 * 69 * @jls 6.6 Access Control 70 * @since 1.2 71 * @revised 9 72 * @spec JPMS 73 */ 74 public class AccessibleObject implements AnnotatedElement { 75 76 /** 77 * The Permission object that is used to check whether a client 78 * has sufficient privilege to defeat Java language access 79 * control checks. 80 */ 81 private static final java.security.Permission ACCESS_PERMISSION = 82 new ReflectPermission("suppressAccessChecks"); 83 84 static void checkPermission() { 85 SecurityManager sm = System.getSecurityManager(); 86 if (sm != null) sm.checkPermission(ACCESS_PERMISSION); 87 } 88 89 /** 90 * Convenience method to set the {@code accessible} flag for an 91 * array of reflected objects with a single security check (for efficiency). 92 * 93 * <p> This method may be used to enable access to all reflected objects in 94 * the array when access to each reflected object can be enabled as 95 * specified by {@link #setAccessible(boolean) setAccessible(boolean)}. </p> 96 * 97 * <p>If there is a security manager, its 98 * {@code checkPermission} method is first called with a 99 * {@code ReflectPermission("suppressAccessChecks")} permission. 100 * 101 * <p>A {@code SecurityException} is also thrown if any of the elements of 102 * the input {@code array} is a {@link java.lang.reflect.Constructor} 103 * object for the class {@code java.lang.Class} and {@code flag} is true. 104 * 105 * @param array the array of AccessibleObjects 106 * @param flag the new value for the {@code accessible} flag 107 * in each object 108 * @throws InaccessibleObjectException if access cannot be enabled for all 109 * objects in the array 110 * @throws SecurityException if the request is denied by the security manager 111 * or an element in the array is a constructor for {@code 112 * java.lang.Class} 113 * @see SecurityManager#checkPermission 114 * @see ReflectPermission 115 * @revised 9 116 * @spec JPMS 117 */ 118 @CallerSensitive 119 public static void setAccessible(AccessibleObject[] array, boolean flag) { 120 checkPermission(); 121 if (flag) { 122 Class<?> caller = Reflection.getCallerClass(); 123 array = array.clone(); 124 for (AccessibleObject ao : array) { 125 ao.checkCanSetAccessible(caller); 126 } 127 } 128 for (AccessibleObject ao : array) { 129 ao.setAccessible0(flag); 130 } 131 } 132 133 /** 134 * Set the {@code accessible} flag for this reflected object to 135 * the indicated boolean value. A value of {@code true} indicates that 136 * the reflected object should suppress checks for Java language access 137 * control when it is used. A value of {@code false} indicates that 138 * the reflected object should enforce checks for Java language access 139 * control when it is used, with the variation noted in the class description. 140 * 141 * <p> This method may be used by a caller in class {@code C} to enable 142 * access to a {@link Member member} of {@link Member#getDeclaringClass() 143 * declaring class} {@code D} if any of the following hold: </p> 144 * 145 * <ul> 146 * <li> {@code C} and {@code D} are in the same module. </li> 147 * 148 * <li> The member is {@code public} and {@code D} is {@code public} in 149 * a package that the module containing {@code D} {@link 150 * Module#isExported(String,Module) exports} to at least the module 151 * containing {@code C}. </li> 152 * 153 * <li> The member is {@code protected} {@code static}, {@code D} is 154 * {@code public} in a package that the module containing {@code D} 155 * exports to at least the module containing {@code C}, and {@code C} 156 * is a subclass of {@code D}. </li> 157 * 158 * <li> {@code D} is in a package that the module containing {@code D} 159 * {@link Module#isOpen(String,Module) opens} to at least the module 160 * containing {@code C}. 161 * All packages in unnamed and open modules are open to all modules and 162 * so this method always succeeds when {@code D} is in an unnamed or 163 * open module. </li> 164 * </ul> 165 * 166 * <p> This method cannot be used to enable access to private members, 167 * members with default (package) access, protected instance members, or 168 * protected constructors when the declaring class is in a different module 169 * to the caller and the package containing the declaring class is not open 170 * to the caller's module. </p> 171 * 172 * <p> If there is a security manager, its 173 * {@code checkPermission} method is first called with a 174 * {@code ReflectPermission("suppressAccessChecks")} permission. 175 * 176 * @param flag the new value for the {@code accessible} flag 177 * @throws InaccessibleObjectException if access cannot be enabled 178 * @throws SecurityException if the request is denied by the security manager 179 * @see #trySetAccessible 180 * @see java.lang.invoke.MethodHandles#privateLookupIn 181 * @revised 9 182 * @spec JPMS 183 */ 184 @CallerSensitive // overrides in Method/Field/Constructor are @CS 185 public void setAccessible(boolean flag) { 186 AccessibleObject.checkPermission(); 187 setAccessible0(flag); 188 } 189 190 /** 191 * Sets the accessible flag and returns the new value 192 */ 193 boolean setAccessible0(boolean flag) { 194 this.override = flag; 195 return flag; 196 } 197 198 /** 199 * Set the {@code accessible} flag for this reflected object to {@code true} 200 * if possible. This method sets the {@code accessible} flag, as if by 201 * invoking {@link #setAccessible(boolean) setAccessible(true)}, and returns 202 * the possibly-updated value for the {@code accessible} flag. If access 203 * cannot be enabled, i.e. the checks or Java language access control cannot 204 * be suppressed, this method returns {@code false} (as opposed to {@code 205 * setAccessible(true)} throwing {@code InaccessibleObjectException} when 206 * it fails). 207 * 208 * <p> This method is a no-op if the {@code accessible} flag for 209 * this reflected object is {@code true}. 210 * 211 * <p> For example, a caller can invoke {@code trySetAccessible} 212 * on a {@code Method} object for a private instance method 213 * {@code p.T::privateMethod} to suppress the checks for Java language access 214 * control when the {@code Method} is invoked. 215 * If {@code p.T} class is in a different module to the caller and 216 * package {@code p} is open to at least the caller's module, 217 * the code below successfully sets the {@code accessible} flag 218 * to {@code true}. 219 * 220 * <pre> 221 * {@code 222 * p.T obj = ....; // instance of p.T 223 * : 224 * Method m = p.T.class.getDeclaredMethod("privateMethod"); 225 * if (m.trySetAccessible()) { 226 * m.invoke(obj); 227 * } else { 228 * // package p is not opened to the caller to access private member of T 229 * ... 230 * } 231 * }</pre> 232 * 233 * <p> If there is a security manager, its {@code checkPermission} method 234 * is first called with a {@code ReflectPermission("suppressAccessChecks")} 235 * permission. </p> 236 * 237 * @return {@code true} if the {@code accessible} flag is set to {@code true}; 238 * {@code false} if access cannot be enabled. 239 * @throws SecurityException if the request is denied by the security manager 240 * 241 * @since 9 242 * @spec JPMS 243 * @see java.lang.invoke.MethodHandles#privateLookupIn 244 */ 245 @CallerSensitive 246 public final boolean trySetAccessible() { 247 AccessibleObject.checkPermission(); 248 249 if (override == true) return true; 250 251 // if it's not a Constructor, Method, Field then no access check 252 if (!Member.class.isInstance(this)) { 253 return setAccessible0(true); 254 } 255 256 // does not allow to suppress access check for Class's constructor 257 Class<?> declaringClass = ((Member) this).getDeclaringClass(); 258 if (declaringClass == Class.class && this instanceof Constructor) { 259 return false; 260 } 261 262 if (checkCanSetAccessible(Reflection.getCallerClass(), 263 declaringClass, 264 false)) { 265 return setAccessible0(true); 266 } else { 267 return false; 268 } 269 } 270 271 272 /** 273 * If the given AccessibleObject is a {@code Constructor}, {@code Method} 274 * or {@code Field} then checks that its declaring class is in a package 275 * that can be accessed by the given caller of setAccessible. 276 */ 277 void checkCanSetAccessible(Class<?> caller) { 278 // do nothing, needs to be overridden by Constructor, Method, Field 279 } 280 281 final void checkCanSetAccessible(Class<?> caller, Class<?> declaringClass) { 282 checkCanSetAccessible(caller, declaringClass, true); 283 } 284 285 private boolean checkCanSetAccessible(Class<?> caller, 286 Class<?> declaringClass, 287 boolean throwExceptionIfDenied) { 288 if (caller == MethodHandle.class) { 289 throw new IllegalCallerException(); // should not happen 290 } 291 292 Module callerModule = caller.getModule(); 293 Module declaringModule = declaringClass.getModule(); 294 295 if (callerModule == declaringModule) return true; 296 if (callerModule == Object.class.getModule()) return true; 297 if (!declaringModule.isNamed()) return true; 298 299 String pn = declaringClass.getPackageName(); 300 int modifiers; 301 if (this instanceof Executable) { 302 modifiers = ((Executable) this).getModifiers(); 303 } else { 304 modifiers = ((Field) this).getModifiers(); 305 } 306 307 // class is public and package is exported to caller 308 boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); 309 if (isClassPublic && declaringModule.isExported(pn, callerModule)) { 310 // member is public 311 if (Modifier.isPublic(modifiers)) { 312 logIfExportedForIllegalAccess(caller, declaringClass); 313 return true; 314 } 315 316 // member is protected-static 317 if (Modifier.isProtected(modifiers) 318 && Modifier.isStatic(modifiers) 319 && isSubclassOf(caller, declaringClass)) { 320 logIfExportedForIllegalAccess(caller, declaringClass); 321 return true; 322 } 323 } 324 325 // package is open to caller 326 if (declaringModule.isOpen(pn, callerModule)) { 327 logIfOpenedForIllegalAccess(caller, declaringClass); 328 return true; 329 } 330 331 if (throwExceptionIfDenied) { 332 // not accessible 333 String msg = "Unable to make "; 334 if (this instanceof Field) 335 msg += "field "; 336 msg += this + " accessible: " + declaringModule + " does not \""; 337 if (isClassPublic && Modifier.isPublic(modifiers)) 338 msg += "exports"; 339 else 340 msg += "opens"; 341 msg += " " + pn + "\" to " + callerModule; 342 InaccessibleObjectException e = new InaccessibleObjectException(msg); 343 if (printStackTraceWhenAccessFails()) { 344 e.printStackTrace(System.err); 345 } 346 throw e; 347 } 348 return false; 349 } 350 351 private boolean isSubclassOf(Class<?> queryClass, Class<?> ofClass) { 352 while (queryClass != null) { 353 if (queryClass == ofClass) { 354 return true; 355 } 356 queryClass = queryClass.getSuperclass(); 357 } 358 return false; 359 } 360 361 private void logIfOpenedForIllegalAccess(Class<?> caller, Class<?> declaringClass) { 362 Module callerModule = caller.getModule(); 363 Module targetModule = declaringClass.getModule(); 364 // callerModule is null during early startup 365 if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) { 366 IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger(); 367 if (logger != null) { 368 logger.logIfOpenedForIllegalAccess(caller, declaringClass, this::toShortString); 369 } 370 } 371 } 372 373 private void logIfExportedForIllegalAccess(Class<?> caller, Class<?> declaringClass) { 374 Module callerModule = caller.getModule(); 375 Module targetModule = declaringClass.getModule(); 376 // callerModule is null during early startup 377 if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) { 378 IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger(); 379 if (logger != null) { 380 logger.logIfExportedForIllegalAccess(caller, declaringClass, this::toShortString); 381 } 382 } 383 } 384 385 /** 386 * Returns a short descriptive string to describe this object in log messages. 387 */ 388 String toShortString() { 389 return toString(); 390 } 391 392 /** 393 * Get the value of the {@code accessible} flag for this reflected object. 394 * 395 * @return the value of the object's {@code accessible} flag 396 * 397 * @deprecated 398 * This method is deprecated because its name hints that it checks 399 * if the reflected object is accessible when it actually indicates 400 * if the checks for Java language access control are suppressed. 401 * This method may return {@code false} on a reflected object that is 402 * accessible to the caller. To test if this reflected object is accessible, 403 * it should use {@link #canAccess(Object)}. 404 * 405 * @revised 9 406 * @spec JPMS 407 */ 408 @Deprecated(since="9") 409 public boolean isAccessible() { 410 return override; 411 } 412 413 /** 414 * Test if the caller can access this reflected object. If this reflected 415 * object corresponds to an instance method or field then this method tests 416 * if the caller can access the given {@code obj} with the reflected object. 417 * For instance methods or fields then the {@code obj} argument must be an 418 * instance of the {@link Member#getDeclaringClass() declaring class}. For 419 * static members and constructors then {@code obj} must be {@code null}. 420 * 421 * <p> This method returns {@code true} if the {@code accessible} flag 422 * is set to {@code true}, i.e. the checks for Java language access control 423 * are suppressed, or if the caller can access the member as 424 * specified in <cite>The Java™ Language Specification</cite>, 425 * with the variation noted in the class description. </p> 426 * 427 * @param obj an instance object of the declaring class of this reflected 428 * object if it is an instance method or field 429 * 430 * @return {@code true} if the caller can access this reflected object. 431 * 432 * @throws IllegalArgumentException 433 * <ul> 434 * <li> if this reflected object is a static member or constructor and 435 * the given {@code obj} is non-{@code null}, or </li> 436 * <li> if this reflected object is an instance method or field 437 * and the given {@code obj} is {@code null} or of type 438 * that is not a subclass of the {@link Member#getDeclaringClass() 439 * declaring class} of the member.</li> 440 * </ul> 441 * 442 * @since 9 443 * @spec JPMS 444 * @jls 6.6 Access Control 445 * @see #trySetAccessible 446 * @see #setAccessible(boolean) 447 */ 448 @CallerSensitive 449 public final boolean canAccess(Object obj) { 450 if (!Member.class.isInstance(this)) { 451 return override; 452 } 453 454 Class<?> declaringClass = ((Member) this).getDeclaringClass(); 455 int modifiers = ((Member) this).getModifiers(); 456 if (!Modifier.isStatic(modifiers) && 457 (this instanceof Method || this instanceof Field)) { 458 if (obj == null) { 459 throw new IllegalArgumentException("null object for " + this); 460 } 461 // if this object is an instance member, the given object 462 // must be a subclass of the declaring class of this reflected object 463 if (!declaringClass.isAssignableFrom(obj.getClass())) { 464 throw new IllegalArgumentException("object is not an instance of " 465 + declaringClass.getName()); 466 } 467 } else if (obj != null) { 468 throw new IllegalArgumentException("non-null object for " + this); 469 } 470 471 // access check is suppressed 472 if (override) return true; 473 474 Class<?> caller = Reflection.getCallerClass(); 475 Class<?> targetClass; 476 if (this instanceof Constructor) { 477 targetClass = declaringClass; 478 } else { 479 targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass(); 480 } 481 return verifyAccess(caller, declaringClass, targetClass, modifiers); 482 } 483 484 /** 485 * Constructor: only used by the Java Virtual Machine. 486 */ 487 protected AccessibleObject() {} 488 489 // Indicates whether language-level access checks are overridden 490 // by this object. Initializes to "false". This field is used by 491 // Field, Method, and Constructor. 492 // 493 // NOTE: for security purposes, this field must not be visible 494 // outside this package. 495 boolean override; 496 497 // Reflection factory used by subclasses for creating field, 498 // method, and constructor accessors. Note that this is called 499 // very early in the bootstrapping process. 500 static final ReflectionFactory reflectionFactory = 501 AccessController.doPrivileged( 502 new ReflectionFactory.GetReflectionFactoryAction()); 503 504 /** 505 * @throws NullPointerException {@inheritDoc} 506 * @since 1.5 507 */ 508 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 509 throw new AssertionError("All subclasses should override this method"); 510 } 511 512 /** 513 * {@inheritDoc} 514 * @throws NullPointerException {@inheritDoc} 515 * @since 1.5 516 */ 517 @Override 518 public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { 519 return AnnotatedElement.super.isAnnotationPresent(annotationClass); 520 } 521 522 /** 523 * @throws NullPointerException {@inheritDoc} 524 * @since 1.8 525 */ 526 @Override 527 public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { 528 throw new AssertionError("All subclasses should override this method"); 529 } 530 531 /** 532 * @since 1.5 533 */ 534 public Annotation[] getAnnotations() { 535 return getDeclaredAnnotations(); 536 } 537 538 /** 539 * @throws NullPointerException {@inheritDoc} 540 * @since 1.8 541 */ 542 @Override 543 public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) { 544 // Only annotations on classes are inherited, for all other 545 // objects getDeclaredAnnotation is the same as 546 // getAnnotation. 547 return getAnnotation(annotationClass); 548 } 549 550 /** 551 * @throws NullPointerException {@inheritDoc} 552 * @since 1.8 553 */ 554 @Override 555 public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) { 556 // Only annotations on classes are inherited, for all other 557 // objects getDeclaredAnnotationsByType is the same as 558 // getAnnotationsByType. 559 return getAnnotationsByType(annotationClass); 560 } 561 562 /** 563 * @since 1.5 564 */ 565 public Annotation[] getDeclaredAnnotations() { 566 throw new AssertionError("All subclasses should override this method"); 567 } 568 569 570 // Shared access checking logic. 571 572 // For non-public members or members in package-private classes, 573 // it is necessary to perform somewhat expensive security checks. 574 // If the security check succeeds for a given class, it will 575 // always succeed (it is not affected by the granting or revoking 576 // of permissions); we speed up the check in the common case by 577 // remembering the last Class for which the check succeeded. 578 // 579 // The simple security check for Constructor is to see if 580 // the caller has already been seen, verified, and cached. 581 // (See also Class.newInstance(), which uses a similar method.) 582 // 583 // A more complicated security check cache is needed for Method and Field 584 // The cache can be either null (empty cache), a 2-array of {caller,targetClass}, 585 // or a caller (with targetClass implicitly equal to memberClass). 586 // In the 2-array case, the targetClass is always different from the memberClass. 587 volatile Object securityCheckCache; 588 589 final void checkAccess(Class<?> caller, Class<?> memberClass, 590 Class<?> targetClass, int modifiers) 591 throws IllegalAccessException 592 { 593 if (!verifyAccess(caller, memberClass, targetClass, modifiers)) { 594 IllegalAccessException e = Reflection.newIllegalAccessException( 595 caller, memberClass, targetClass, modifiers); 596 if (printStackTraceWhenAccessFails()) { 597 e.printStackTrace(System.err); 598 } 599 throw e; 600 } 601 } 602 603 final boolean verifyAccess(Class<?> caller, Class<?> memberClass, 604 Class<?> targetClass, int modifiers) 605 { 606 if (caller == memberClass) { // quick check 607 return true; // ACCESS IS OK 608 } 609 Object cache = securityCheckCache; // read volatile 610 if (targetClass != null // instance member or constructor 611 && Modifier.isProtected(modifiers) 612 && targetClass != memberClass) { 613 // Must match a 2-list of { caller, targetClass }. 614 if (cache instanceof Class[]) { 615 Class<?>[] cache2 = (Class<?>[]) cache; 616 if (cache2[1] == targetClass && 617 cache2[0] == caller) { 618 return true; // ACCESS IS OK 619 } 620 // (Test cache[1] first since range check for [1] 621 // subsumes range check for [0].) 622 } 623 } else if (cache == caller) { 624 // Non-protected case (or targetClass == memberClass or static member). 625 return true; // ACCESS IS OK 626 } 627 628 // If no return, fall through to the slow path. 629 return slowVerifyAccess(caller, memberClass, targetClass, modifiers); 630 } 631 632 // Keep all this slow stuff out of line: 633 private boolean slowVerifyAccess(Class<?> caller, Class<?> memberClass, 634 Class<?> targetClass, int modifiers) 635 { 636 if (!Reflection.verifyMemberAccess(caller, memberClass, targetClass, modifiers)) { 637 // access denied 638 return false; 639 } 640 641 // access okay 642 logIfExportedForIllegalAccess(caller, memberClass); 643 644 // Success: Update the cache. 645 Object cache = (targetClass != null 646 && Modifier.isProtected(modifiers) 647 && targetClass != memberClass) 648 ? new Class<?>[] { caller, targetClass } 649 : caller; 650 651 // Note: The two cache elements are not volatile, 652 // but they are effectively final. The Java memory model 653 // guarantees that the initializing stores for the cache 654 // elements will occur before the volatile write. 655 securityCheckCache = cache; // write volatile 656 return true; 657 } 658 659 // true to print a stack trace when access fails 660 private static volatile boolean printStackWhenAccessFails; 661 662 // true if printStack* values are initialized 663 private static volatile boolean printStackPropertiesSet; 664 665 /** 666 * Returns true if a stack trace should be printed when access fails. 667 */ 668 private static boolean printStackTraceWhenAccessFails() { 669 if (!printStackPropertiesSet && VM.initLevel() >= 1) { 670 String s = GetPropertyAction.privilegedGetProperty( 671 "sun.reflect.debugModuleAccessChecks"); 672 if (s != null) { 673 printStackWhenAccessFails = !s.equalsIgnoreCase("false"); 674 } 675 printStackPropertiesSet = true; 676 } 677 return printStackWhenAccessFails; 678 } 679 }