1 /*
   2  * Copyright (c) 2019, 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  * @compile getPermittedSubtypes.jcod
  27  * @run main getPermittedSubtypesTest
  28  */
  29 
  30 import java.lang.constant.ClassDesc;
  31 import java.util.ArrayList;
  32 
  33 // Test Class.getPermittedSubtpes() and Class.isSealed() APIs.
  34 public class getPermittedSubtypesTest {
  35 
  36     sealed class Sealed1 permits Sub1 {}
  37 
  38     class Sub1 extends Sealed1 {}
  39 
  40     sealed interface SealedI1 permits notSealed, Sub1, Extender {}
  41 
  42     interface Extender extends SealedI1 { }
  43 
  44     class notSealed implements SealedI1 {}
  45 
  46     sealed class noPermits {}
  47 
  48     final class Final4 {}
  49 
  50     public static void testSealedInfo(Class<?> c, String[] expected) {
  51         Object[] permitted = c.getPermittedSubtypes();
  52 
  53         if (permitted.length != expected.length) {
  54             throw new RuntimeException(
  55                 "Unexpected number of permitted subtypes for: " + c.toString());
  56         }
  57 
  58         if (permitted.length > 0) {
  59             if (!c.isSealed()) {
  60                 throw new RuntimeException("Expected sealed type: " + c.toString());
  61             }
  62 
  63             // Create ArrayList of permitted subtypes class names.
  64             ArrayList<String> permittedNames = new ArrayList<String>();
  65             for (int i = 0; i < permitted.length; i++) {
  66                 permittedNames.add(((ClassDesc)permitted[i]).descriptorString());
  67             }
  68 
  69             if (permittedNames.size() != expected.length) {
  70                 throw new RuntimeException(
  71                     "Unexpected number of permitted names for: " + c.toString());
  72             }
  73 
  74             // Check that expected class names are in the permitted subtypes list.
  75             for (int i = 0; i < expected.length; i++) {
  76                 if (!permittedNames.contains(expected[i])) {
  77                     throw new RuntimeException(
  78                          "Expected class not found in permitted subtypes list, super type: " +
  79                          c.getName() + ", expected class: " + expected[i]);
  80                 }
  81             }
  82         } else {
  83             // Must not be sealed if no permitted subtypes.
  84             if (c.isSealed()) {
  85                 throw new RuntimeException("Unexpected sealed type: " + c.toString());
  86             }
  87         }
  88     }
  89 
  90     public static void main(String... args) throws Throwable {
  91         testSealedInfo(SealedI1.class, new String[] {"LgetPermittedSubtypesTest$notSealed;",
  92                                                      "LgetPermittedSubtypesTest$Sub1;",
  93                                                      "LgetPermittedSubtypesTest$Extender;"});
  94         testSealedInfo(Sealed1.class, new String[] {"LgetPermittedSubtypesTest$Sub1;"});
  95         testSealedInfo(noPermits.class, new String[] { });
  96         testSealedInfo(Final4.class, new String[] { });
  97         testSealedInfo(notSealed.class, new String[] { });
  98 
  99         // Test class with PermittedSubtypes attribute but old class file version.
 100         testSealedInfo(oldClassFile.class, new String[] { });
 101 
 102         // Test class with empty PermittedSubtypes attribute.
 103         testSealedInfo(noSubtypes.class, new String[] { });
 104 
 105         // Test returning names of non-existing classes.
 106         testSealedInfo(noLoadSubtypes.class, new String[]{"LiDontExist;", "LI/Dont/Exist/Either;"});
 107 
 108         // Test that loading a class with a corrupted PermittedSubtypes attribute
 109         // causes a ClassFormatError.
 110         try {
 111             Class.forName("badPermittedAttr");
 112             throw new RuntimeException("Expected ClasFormatError exception not thrown");
 113         } catch (ClassFormatError cfe) {
 114             if (!cfe.getMessage().contains("Permitted subtype class_info_index 15 has bad constant type")) {
 115                 throw new RuntimeException("Unexpected ClassFormatError exception: " + cfe.getMessage());
 116             }
 117         }
 118     }
 119 }