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