58
58
import java .util .Arrays ;
59
59
import java .util .Collection ;
60
60
import java .util .HashMap ;
61
+ import java .util .HashSet ;
61
62
import java .util .LinkedHashMap ;
62
63
import java .util .LinkedHashSet ;
63
64
import java .util .List ;
64
65
import java .util .Map ;
65
66
import java .util .Objects ;
66
67
import java .util .Optional ;
68
+ import java .util .Set ;
67
69
import java .util .stream .Collectors ;
68
70
69
71
import jdk .internal .loader .BootLoader ;
@@ -200,8 +202,6 @@ public final class Class<T> implements java.io.Serializable,
200
202
private static final int ENUM = 0x00004000 ;
201
203
private static final int SYNTHETIC = 0x00001000 ;
202
204
203
- private static final ClassDesc [] EMPTY_CLASS_DESC_ARRAY = new ClassDesc [0 ];
204
-
205
205
private static native void registerNatives ();
206
206
static {
207
207
registerNatives ();
@@ -3020,6 +3020,37 @@ private void checkPackageAccess(SecurityManager sm, final ClassLoader ccl,
3020
3020
}
3021
3021
}
3022
3022
3023
+ /*
3024
+ * Checks if a client loaded in ClassLoader ccl is allowed to access the provided
3025
+ * classes under the current package access policy. If access is denied,
3026
+ * throw a SecurityException.
3027
+ *
3028
+ * NOTE: this method should only be called if a SecurityManager is active
3029
+ * classes must be non-empty
3030
+ * all classes provided must be loaded by the same ClassLoader
3031
+ * NOTE: this method does not support Proxy classes
3032
+ */
3033
+ private static void checkPackageAccessForPermittedSubclasses (SecurityManager sm ,
3034
+ final ClassLoader ccl , Class <?>[] subClasses ) {
3035
+ final ClassLoader cl = subClasses [0 ].getClassLoader0 ();
3036
+
3037
+ if (ReflectUtil .needsPackageAccessCheck (ccl , cl )) {
3038
+ Set <String > packages = new HashSet <>();
3039
+
3040
+ for (Class <?> c : subClasses ) {
3041
+ if (Proxy .isProxyClass (c ))
3042
+ throw new InternalError ("a permitted subclass should not be a proxy class: " + c );
3043
+ String pkg = c .getPackageName ();
3044
+ if (pkg != null && !pkg .isEmpty ()) {
3045
+ packages .add (pkg );
3046
+ }
3047
+ }
3048
+ for (String pkg : packages ) {
3049
+ sm .checkPackageAccess (pkg );
3050
+ }
3051
+ }
3052
+ }
3053
+
3023
3054
/**
3024
3055
* Add a package name prefix if the name is not absolute Remove leading "/"
3025
3056
* if name is absolute
@@ -4357,47 +4388,87 @@ public Optional<ClassDesc> describeConstable() {
4357
4388
* may be removed in a future release, or upgraded to permanent
4358
4389
* features of the Java language.}
4359
4390
*
4360
- * Returns an array containing {@code ClassDesc } objects representing all the
4361
- * direct subclasses or direct implementation classes permitted to extend or
4391
+ * Returns an array containing {@code Class } objects representing the
4392
+ * direct subinterfaces or subclasses permitted to extend or
4362
4393
* implement this class or interface if it is sealed. The order of such elements
4363
4394
* is unspecified. If this {@code Class} object represents a primitive type,
4364
4395
* {@code void}, an array type, or a class or interface that is not sealed,
4365
4396
* an empty array is returned.
4366
4397
*
4367
- * @return an array of class descriptors of all the permitted subclasses of this class or interface
4398
+ * For each class or interface {@code C} which is recorded as a permitted
4399
+ * direct subinterface or subclass of this class or interface,
4400
+ * this method attempts to obtain the {@code Class}
4401
+ * object for {@code C} (using {@linkplain #getClassLoader() the defining class
4402
+ * loader} of the current {@code Class} object).
4403
+ * The {@code Class} objects which can be obtained and which are direct
4404
+ * subinterfaces or subclasses of this class or interface,
4405
+ * are indicated by elements of the returned array. If a {@code Class} object
4406
+ * cannot be obtained, it is silently ignored, and not included in the result
4407
+ * array.
4408
+ *
4409
+ * @return an array of {@code Class} objects of the permitted subclasses of this class or interface
4410
+ *
4411
+ * @throws SecurityException
4412
+ * If a security manager, <i>s</i>, is present and the caller's
4413
+ * class loader is not the same as or an ancestor of the class
4414
+ * loader for that returned class and invocation of {@link
4415
+ * SecurityManager#checkPackageAccess s.checkPackageAccess()}
4416
+ * denies access to the package of any class in the returned array.
4368
4417
*
4369
4418
* @jls 8.1 Class Declarations
4370
4419
* @jls 9.1 Interface Declarations
4371
4420
* @since 15
4372
4421
*/
4373
4422
@ jdk .internal .PreviewFeature (feature =jdk .internal .PreviewFeature .Feature .SEALED_CLASSES , essentialAPI =false )
4374
- public ClassDesc [] permittedSubclasses () {
4375
- String [] subclassNames ;
4376
- if (isArray () || isPrimitive () || (subclassNames = getPermittedSubclasses0 ()).length == 0 ) {
4377
- return EMPTY_CLASS_DESC_ARRAY ;
4378
- }
4379
- ClassDesc [] constants = new ClassDesc [subclassNames .length ];
4380
- int i = 0 ;
4381
- for (String subclassName : subclassNames ) {
4382
- try {
4383
- constants [i ++] = ClassDesc .of (subclassName .replace ('/' , '.' ));
4384
- } catch (IllegalArgumentException iae ) {
4385
- throw new InternalError ("Invalid type in permitted subclasses information: " + subclassName , iae );
4423
+ @ CallerSensitive
4424
+ public Class <?>[] getPermittedSubclasses () {
4425
+ Class <?>[] subClasses ;
4426
+ if (isArray () || isPrimitive () || (subClasses = getPermittedSubclasses0 ()).length == 0 ) {
4427
+ return EMPTY_CLASS_ARRAY ;
4428
+ }
4429
+ if (subClasses .length > 0 ) {
4430
+ if (Arrays .stream (subClasses ).anyMatch (c -> !isDirectSubType (c ))) {
4431
+ subClasses = Arrays .stream (subClasses )
4432
+ .filter (this ::isDirectSubType )
4433
+ .toArray (s -> new Class <?>[s ]);
4386
4434
}
4387
4435
}
4388
- return constants ;
4436
+ if (subClasses .length > 0 ) {
4437
+ // If we return some classes we need a security check:
4438
+ SecurityManager sm = System .getSecurityManager ();
4439
+ if (sm != null ) {
4440
+ checkPackageAccessForPermittedSubclasses (sm ,
4441
+ ClassLoader .getClassLoader (Reflection .getCallerClass ()),
4442
+ subClasses );
4443
+ }
4444
+ }
4445
+ return subClasses ;
4446
+ }
4447
+
4448
+ private boolean isDirectSubType (Class <?> c ) {
4449
+ if (isInterface ()) {
4450
+ for (Class <?> i : c .getInterfaces (/* cloneArray */ false )) {
4451
+ if (i == this ) {
4452
+ return true ;
4453
+ }
4454
+ }
4455
+ } else {
4456
+ return c .getSuperclass () == this ;
4457
+ }
4458
+ return false ;
4389
4459
}
4390
4460
4391
4461
/**
4392
- * * {@preview Associated with sealed classes, a preview feature of the Java language.
4462
+ * {@preview Associated with sealed classes, a preview feature of the Java language.
4393
4463
*
4394
4464
* This method is associated with <i>sealed classes</i>, a preview
4395
4465
* feature of the Java language. Preview features
4396
4466
* may be removed in a future release, or upgraded to permanent
4397
4467
* features of the Java language.}
4398
4468
*
4399
- * Returns {@code true} if and only if this {@code Class} object represents a sealed class or interface.
4400
- * If this {@code Class} object represents a primitive type, {@code void}, or an array type, this method returns
4469
+ * Returns {@code true} if and only if this {@code Class} object represents
4470
+ * a sealed class or interface. If this {@code Class} object represents a
4471
+ * primitive type, {@code void}, or an array type, this method returns
4401
4472
* {@code false}.
4402
4473
*
4403
4474
* @return {@code true} if and only if this {@code Class} object represents a sealed class or interface.
@@ -4412,8 +4483,8 @@ public boolean isSealed() {
4412
4483
if (isArray () || isPrimitive ()) {
4413
4484
return false ;
4414
4485
}
4415
- return permittedSubclasses ().length != 0 ;
4486
+ return getPermittedSubclasses ().length != 0 ;
4416
4487
}
4417
4488
4418
- private native String [] getPermittedSubclasses0 ();
4489
+ private native Class <?> [] getPermittedSubclasses0 ();
4419
4490
}
0 commit comments