1 /* 2 * Copyright (c) 2013, 2024, 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 6298888 6992705 8161500 6304578 8322878 27 * @summary Check Class.toGenericString() 28 * @enablePreview 29 * @compile GenericStringTest.java 30 * @run main/othervm GenericStringTest 31 */ 32 33 import java.lang.reflect.*; 34 import java.lang.annotation.*; 35 import java.util.*; 36 37 @ExpectedGenericString("public class GenericStringTest") 38 public class GenericStringTest { 39 public Map<String, Integer>[] mixed = null; 40 public Map<String, Integer>[][] mixed2 = null; 41 42 private static record PlatformTestCase(Class<?> clazz, String expected) {} 43 44 public static void main(String... args) throws ReflectiveOperationException { 45 int failures = 0; 46 47 String[][] nested = {{""}}; 48 int[][] intArray = {{1}}; 49 50 List<PlatformTestCase> platformTestCases = 51 List.of(new PlatformTestCase(int.class, "int"), 52 new PlatformTestCase(void.class, "void"), 53 new PlatformTestCase(args.getClass(), "java.lang.String[]"), 54 new PlatformTestCase(nested.getClass(), "java.lang.String[][]"), 55 new PlatformTestCase(intArray.getClass(), "int[][]"), 56 57 new PlatformTestCase(java.lang.Enum.class, 58 "public abstract class java.lang.Enum<E extends java.lang.Enum<E>>"), 59 new PlatformTestCase(java.util.Map.class, 60 "public abstract interface java.util.Map<K,V>"), 61 new PlatformTestCase(java.util.EnumMap.class, 62 "public class java.util.EnumMap<K extends java.lang.Enum<K>,V>"), 63 new PlatformTestCase(java.util.EventListenerProxy.class, 64 "public abstract class java.util.EventListenerProxy<T extends java.util.EventListener>"), 65 66 // Sealed class 67 new PlatformTestCase(java.lang.ref.Reference.class, 68 "public abstract sealed class java.lang.ref.Reference<T>"), 69 // non-sealed class 70 new PlatformTestCase(java.lang.ref.WeakReference.class, 71 "public non-sealed class java.lang.ref.WeakReference<T>") 72 ); 73 74 for (PlatformTestCase platformTestCase : platformTestCases) { 75 failures += checkToGenericString(platformTestCase.clazz, 76 platformTestCase.expected); 77 } 78 79 Field f = GenericStringTest.class.getDeclaredField("mixed"); 80 // The expected value includes "<K,V>" rather than 81 // "<...String,...Integer>" since the Class object rather than 82 // Type objects is being queried. 83 failures += checkToGenericString(f.getType(), "java.util.Map<K,V>[]"); 84 f = GenericStringTest.class.getDeclaredField("mixed2"); 85 failures += checkToGenericString(f.getType(), "java.util.Map<K,V>[][]"); 86 87 for(Class<?> clazz : List.of(GenericStringTest.class, 88 AnInterface.class, 89 LocalMap.class, 90 AnEnum.class, 91 AnotherEnum.class, 92 AValueClass.class, 93 94 SealedRootClass.class, 95 SealedRootClass.ChildA.class, 96 SealedRootClass.ChildB.class, 97 SealedRootClass.ChildB.GrandChildAB.class, 98 SealedRootClass.ChildC.class, 99 SealedRootClass.ChildC.GrandChildACA.class, 100 SealedRootClass.ChildC.GrandChildACB.class, 101 SealedRootClass.ChildC.GrandChildACC.class, 102 SealedRootClass.ChildC.GrandChildACC.GreatGrandChildACCA.class, 103 SealedRootClass.ChildC.GrandChildACC.GreatGrandChildACCB.class, 104 105 SealedRootIntf.class, 106 SealedRootIntf.ChildA.class, 107 SealedRootIntf.ChildB.class, 108 SealedRootIntf.ChildB.GrandChildAB.class, 109 SealedRootIntf.ChildC.class, 110 SealedRootIntf.ChildC.GrandChildACA.class, 111 SealedRootIntf.ChildC.GrandChildACB.class, 112 SealedRootIntf.ChildC.GrandChildACC.class, 113 SealedRootIntf.ChildC.GrandChildACC.GreatGrandChildACCA.class, 114 SealedRootIntf.ChildC.GrandChildACC.GreatGrandChildACCB.class, 115 SealedRootIntf.IntfA.class, 116 SealedRootIntf.IntfA.IntfAImpl.class, 117 SealedRootIntf.IntfB.class, 118 SealedRootIntf.IntfB.IntfAImpl.class)) { 119 failures += checkToGenericString(clazz, clazz.getAnnotation(ExpectedGenericString.class).value()); 120 } 121 122 if (failures > 0) { 123 throw new RuntimeException(); 124 } 125 } 126 127 private static int checkToGenericString(Class<?> clazz, String expected) { 128 String genericString = clazz.toGenericString(); 129 if (!genericString.equals(expected)) { 130 System.err.printf("Unexpected Class.toGenericString output; expected %n\t'%s',%n got %n\t'%s'.%n", 131 expected, 132 genericString); 133 return 1; 134 } else 135 return 0; 136 } 137 } 138 139 @Retention(RetentionPolicy.RUNTIME) 140 @interface ExpectedGenericString { 141 String value(); 142 } 143 144 @ExpectedGenericString("abstract interface AnInterface") 145 strictfp interface AnInterface {} 146 147 @ExpectedGenericString("abstract interface LocalMap<K,V>") 148 interface LocalMap<K,V> {} 149 150 @ExpectedGenericString("final enum AnEnum") 151 enum AnEnum { 152 FOO; 153 } 154 155 // If an enum class has a specialized enum constant, that is compiled 156 // by having the enum class as being sealed rather than final. See JLS 157 // 8.9 Enum Classes. 158 @ExpectedGenericString("sealed enum AnotherEnum") 159 enum AnotherEnum { 160 BAR{}; 161 } 162 163 @ExpectedGenericString("final value class AValueClass<E>") 164 value class AValueClass<E> {} 165 166 // Test cases for sealed/non-sealed _class_ hierarchy. 167 @ExpectedGenericString("sealed class SealedRootClass") 168 sealed class SealedRootClass 169 permits 170 SealedRootClass.ChildA, 171 SealedRootClass.ChildB, 172 SealedRootClass.ChildC { 173 174 @ExpectedGenericString("final class SealedRootClass$ChildA") 175 final class ChildA extends SealedRootClass {} 176 177 @ExpectedGenericString("sealed class SealedRootClass$ChildB") 178 sealed class ChildB extends SealedRootClass permits SealedRootClass.ChildB.GrandChildAB { 179 @ExpectedGenericString("final class SealedRootClass$ChildB$GrandChildAB") 180 final class GrandChildAB extends ChildB {} 181 } 182 183 @ExpectedGenericString("non-sealed class SealedRootClass$ChildC") 184 non-sealed class ChildC extends SealedRootClass { 185 // The subclasses of ChildC do not themselves have to be 186 // sealed, non-sealed, or final. 187 @ExpectedGenericString("class SealedRootClass$ChildC$GrandChildACA") 188 class GrandChildACA extends ChildC {} 189 190 @ExpectedGenericString("final class SealedRootClass$ChildC$GrandChildACB") 191 final class GrandChildACB extends ChildC {} 192 193 @ExpectedGenericString("sealed class SealedRootClass$ChildC$GrandChildACC") 194 sealed class GrandChildACC extends ChildC { 195 @ExpectedGenericString("final class SealedRootClass$ChildC$GrandChildACC$GreatGrandChildACCA") 196 final class GreatGrandChildACCA extends GrandChildACC {} 197 198 @ExpectedGenericString("non-sealed class SealedRootClass$ChildC$GrandChildACC$GreatGrandChildACCB") 199 non-sealed class GreatGrandChildACCB extends GrandChildACC {} 200 } 201 } 202 } 203 204 // Test cases for sealed/non-sealed _interface_ hierarchy. 205 @ExpectedGenericString("abstract sealed interface SealedRootIntf") 206 sealed interface SealedRootIntf 207 permits 208 SealedRootIntf.ChildA, 209 SealedRootIntf.ChildB, 210 SealedRootIntf.ChildC, 211 212 SealedRootIntf.IntfA, 213 SealedRootIntf.IntfB { 214 215 @ExpectedGenericString("public static final class SealedRootIntf$ChildA") 216 final class ChildA implements SealedRootIntf {} 217 218 @ExpectedGenericString("public static sealed class SealedRootIntf$ChildB") 219 sealed class ChildB implements SealedRootIntf permits SealedRootIntf.ChildB.GrandChildAB { 220 @ExpectedGenericString("final class SealedRootIntf$ChildB$GrandChildAB") 221 final class GrandChildAB extends ChildB {} 222 } 223 224 @ExpectedGenericString("public static non-sealed class SealedRootIntf$ChildC") 225 non-sealed class ChildC implements SealedRootIntf { 226 // The subclasses of ChildC do not themselves have to be 227 // sealed, non-sealed, or final. 228 @ExpectedGenericString("class SealedRootIntf$ChildC$GrandChildACA") 229 class GrandChildACA extends ChildC {} 230 231 @ExpectedGenericString("final class SealedRootIntf$ChildC$GrandChildACB") 232 final class GrandChildACB extends ChildC {} 233 234 @ExpectedGenericString("sealed class SealedRootIntf$ChildC$GrandChildACC") 235 sealed class GrandChildACC extends ChildC { 236 @ExpectedGenericString("final class SealedRootIntf$ChildC$GrandChildACC$GreatGrandChildACCA") 237 final class GreatGrandChildACCA extends GrandChildACC {} 238 239 @ExpectedGenericString("non-sealed class SealedRootIntf$ChildC$GrandChildACC$GreatGrandChildACCB") 240 non-sealed class GreatGrandChildACCB extends GrandChildACC {} 241 } 242 } 243 244 @ExpectedGenericString("public abstract static sealed interface SealedRootIntf$IntfA") 245 sealed interface IntfA extends SealedRootIntf { 246 @ExpectedGenericString("public static non-sealed class SealedRootIntf$IntfA$IntfAImpl") 247 non-sealed class IntfAImpl implements IntfA {} 248 } 249 250 @ExpectedGenericString("public abstract static non-sealed interface SealedRootIntf$IntfB") 251 non-sealed interface IntfB extends SealedRootIntf { 252 // Check that non-sealing can be allowed with a second superinterface being sealed. 253 @ExpectedGenericString("public static non-sealed class SealedRootIntf$IntfB$IntfAImpl") 254 non-sealed class IntfAImpl implements IntfB, IntfA {} 255 } 256 }