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 }
--- EOF ---