1 /*
2  * Copyright (c) 2020, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8225056
27  * @compile GetPermittedSubclasses.jcod
28  * @compile --enable-preview -source ${jdk.version} GetPermittedSubclassesTest.java
29  * @run main/othervm --enable-preview GetPermittedSubclassesTest
30  */
31 
32 import java.lang.constant.ClassDesc;
33 import java.util.ArrayList;
34 
35 // Test Class GetPermittedSubtpes() and Class.isSealed() APIs.
36 public class GetPermittedSubclassesTest {
37 
38     sealed class Sealed1 permits Sub1 {}
39 
40     final class Sub1 extends Sealed1 implements SealedI1 {}
41 
42     sealed interface SealedI1 permits NotSealed, Sub1, Extender {}
43 
44     non-sealed interface Extender extends SealedI1 { }
45 
46     final class FinalC implements Extender {}
47 
48     final class NotSealed implements SealedI1 {}
49 
50     final class Final4 {}
51 
testSealedInfo(Class<?> c, String[] expected)52     public static void testSealedInfo(Class<?> c, String[] expected) {
53         Object[] permitted = c.permittedSubclasses();
54 
55         if (permitted.length != expected.length) {
56             throw new RuntimeException(
57                 "Unexpected number of permitted subclasses for: " + c.toString());
58         }
59 
60         if (permitted.length > 0) {
61             if (!c.isSealed()) {
62                 throw new RuntimeException("Expected sealed class: " + c.toString());
63             }
64 
65             // Create ArrayList of permitted subclasses class names.
66             ArrayList<String> permittedNames = new ArrayList<String>();
67             for (int i = 0; i < permitted.length; i++) {
68                 permittedNames.add(((ClassDesc)permitted[i]).descriptorString());
69             }
70 
71             if (permittedNames.size() != expected.length) {
72                 throw new RuntimeException(
73                     "Unexpected number of permitted names for: " + c.toString());
74             }
75 
76             // Check that expected class names are in the permitted subclasses list.
77             for (int i = 0; i < expected.length; i++) {
78                 if (!permittedNames.contains(expected[i])) {
79                     throw new RuntimeException(
80                          "Expected class not found in permitted subclases list, super class: " +
81                          c.getName() + ", expected class: " + expected[i]);
82                 }
83             }
84         } else {
85             // Must not be sealed if no permitted subclasses.
86             if (c.isSealed()) {
87                 throw new RuntimeException("Unexpected sealed class: " + c.toString());
88             }
89         }
90     }
91 
testBadSealedClass(String className, String expectedCFEMessage)92     public static void testBadSealedClass(String className, String expectedCFEMessage) throws Throwable {
93         try {
94             Class.forName(className);
95             throw new RuntimeException("Expected ClassFormatError exception not thrown for " + className);
96         } catch (ClassFormatError cfe) {
97             if (!cfe.getMessage().contains(expectedCFEMessage)) {
98                 throw new RuntimeException(
99                     "Class " + className + " got unexpected ClassFormatError exception: " + cfe.getMessage());
100             }
101         }
102     }
103 
main(String... args)104     public static void main(String... args) throws Throwable {
105         testSealedInfo(SealedI1.class, new String[] {"LGetPermittedSubclassesTest$NotSealed;",
106                                                      "LGetPermittedSubclassesTest$Sub1;",
107                                                      "LGetPermittedSubclassesTest$Extender;"});
108         testSealedInfo(Sealed1.class, new String[] {"LGetPermittedSubclassesTest$Sub1;"});
109         testSealedInfo(Final4.class, new String[] { });
110         testSealedInfo(NotSealed.class, new String[] { });
111 
112         // Test class with PermittedSubclasses attribute but old class file version.
113         testSealedInfo(OldClassFile.class, new String[] { });
114 
115         // Test class with an empty PermittedSubclasses attribute.
116         testBadSealedClass("NoSubclasses", "PermittedSubclasses attribute is empty");
117 
118         // Test returning names of non-existing classes.
119         testSealedInfo(NoLoadSubclasses.class, new String[]{"LiDontExist;", "LI/Dont/Exist/Either;"});
120 
121         // Test that loading a class with a corrupted PermittedSubclasses attribute
122         // causes a ClassFormatError.
123         testBadSealedClass("BadPermittedAttr",
124                           "Permitted subclass class_info_index 15 has bad constant type");
125 
126         // Test that loading a sealed final class with a PermittedSubclasses
127         // attribute causes a ClassFormatError.
128         testBadSealedClass("SealedButFinal", "PermittedSubclasses attribute in final class");
129 
130         // Test that loading a sealed class with a bad class name in its PermittedSubclasses
131         // attribute causes a ClassFormatError.
132         testBadSealedClass("BadPermittedSubclassEntry", "Illegal class name \"iDont;;Exist\" in class file");
133 
134         // Test that loading a sealed class with an empty class name in its PermittedSubclasses
135         // attribute causes a ClassFormatError.
136         testBadSealedClass("EmptyPermittedSubclassEntry", "Illegal class name \"\" in class file");
137     }
138 }
139