1 /*
2 * Copyright (c) 2022, 2025, 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 * @test
25 * @bug 8194743 8345438 8356551 8349754
26 * @summary Test valid placements of super()/this() in constructors
27 * @run main SuperInitGood
28 * @build InitializationWarningTester
29 * @run main InitializationWarningTester SuperInitGood SuperInitGoodWarnings.out
30 */
31
32 import java.util.concurrent.atomic.AtomicReference;
33
34 public class SuperInitGood {
35
36 SuperInitGood(Object obj) {
37 }
38
39 SuperInitGood(int x) {
40 }
41
42 // Default constructor provided by compiler
43 static class Test0 {
44 }
45
46 // No explicit calls to this()/super()
47 static class Test1 {
48 Test1() {
49 }
50
51 Test1(int a) {
52 this.hashCode();
53 }
54 }
55
56 // Explicit calls to this()/super()
57 static class Test2<T> {
58 static int i;
59 Test2() {
60 this(0);
61 }
62 Test2(int i) {
63 Test2.i = i;
64 super();
65 }
66 Test2(T obj) {
67 this(java.util.Objects.hashCode(obj));
68 }
69 public T get() {
70 return null;
71 }
72 }
73
74 // Explicit this()/super() with stuff in front
75 static class Test3 {
76 int x;
77 final int y;
78 final int z;
79
80 Test3() {
81 new Object().hashCode();
82 new Object().hashCode();
83 super();
84 this.x = new Object().hashCode();
85 this.y = new Object().hashCode() % 17;
86 this.z = this.x + this.y;
87 }
88 }
89
90 // Reference within constructor to outer class that's also my superclass
91 class Test5 extends SuperInitGood {
92 Test5(Object obj) {
93 if (obj == null)
94 throw new IllegalArgumentException();
95 super(SuperInitGood.this); // NOT a 'this' reference
96 }
97 }
98
99 // Initialization blocks
100 class Test6 {
101 final long startTime;
102 final int x;
103 {
104 this.x = 12;
105 }
106 Test6() {
107 long now = System.nanoTime();
108 long then = now + 1000000L;
109 while (System.nanoTime() < then) {
110 try {
111 Thread.sleep(1);
112 } catch (InterruptedException e) {
113 Thread.currentThread().interrupt();
114 break;
115 }
116 }
117 super();
118 this.startTime = now;
119 }
120 }
121
122 // Mix up inner classes, proxies, and super() calls
123 // Copied mostly from UnverifiableInitForNestedLocalClassTest.java
124 public static void test7(final String arg) {
125 final String inlined = " inlined ";
126 class LocalClass {
127 String m() {
128 return "LocalClass " + arg + inlined;
129 }
130
131 class SubClass extends LocalClass {
132 @Override
133 String m() {
134 return "SubClass " + arg + inlined;
135 }
136 }
137
138 class SubSubClass extends SubClass {
139 @Override
140 String m() {
141 return "SubSubClass " + arg + inlined;
142 }
143 }
144
145 class AnotherLocal {
146 class AnotherSub extends LocalClass {
147 AnotherSub() {
148 }
149 AnotherSub(int x) {
150 this((char)x);
151 }
152 AnotherSub(char y) {
153 super();
154 }
155 @Override
156 String m() {
157 return "AnotherSub " + arg + inlined;
158 }
159 }
160 }
161 }
162 }
163
164 // Anonymous inner class
165 public static void test8() {
166 new Test2<Byte>(null) {
167 @Override
168 public Byte get() {
169 return (byte)-1;
170 }
171 };
172 }
173
174 // Qualified super() invocation
175 public static class Test9 extends Test5 {
176
177 public Test9(SuperInitGood implicit, Object obj) {
178 obj.hashCode();
179 implicit.super(obj);
180 }
181 }
182
183 // Copied from WhichImplicitThis6
184 public static class Test10 {
185 private int i;
186 public Test10(int i) {}
187 public class Sub extends Test10 {
188 public Sub() {
189 super(i); // i is not inherited, so it is the enclosing i
190 }
191 }
192 }
193
194 // Two constructors where only one invokes super()
195 public static class Test11 {
196 public Test11() {
197 }
198 public Test11(int x) {
199 super();
200 }
201 }
202
203 // Nested version of the previous test
204 public static class Test12 {
205 Test12() {
206 class Sub {
207 public Sub() {
208 }
209 public Sub(int j) {
210 super();
211 }
212 }
213 }
214 }
215
216 // Nested super()'s requiring initialization code appended
217 public static class Test13 extends SuperInitGood {
218 final int x = new Object().hashCode();
219 Test13() {
220 super(new Object() {
221 public void foo() {
222 class Bar {
223 final int y = new Object().hashCode();
224 Bar() {
225 super();
226 }
227 Bar(int ignored) {
228 }
229 }
230 }
231 });
232 }
233 }
234
235 // Initializer in initializer block
236 public static class Test14 {
237 final int x; // initialized in constructor
238 final int y; // initialized in initialization block
239 final int z = 13; // initialized with intializer value
240 public Test14() {
241 this(0);
242 }
243 public Test14(boolean z) {
244 this.x = z ? 1 : 0;
245 }
246 public Test14(int x) {
247 super();
248 this.x = x;
249 }
250 {
251 this.y = -1;
252 }
253 }
254
255 // Qualified super() invocation with superclass instance
256 public static class Test15 {
257
258 final String name;
259
260 public Test15(String name) {
261 this.name = name;
262 }
263
264 public class Test15b extends Test15 {
265
266 public Test15b(String name) {
267 super(name);
268 }
269
270 public String getName() {
271 return Test15.this.name;
272 }
273 }
274 }
275
276 public static class Test15c extends Test15.Test15b {
277 public Test15c(Test15 a, String name) {
278 a.super(name);
279 }
280 }
281
282 // Mixing up outer instances, proxies, and initializers
283 public static class Test16 {
284
285 final String x = String.valueOf(new Object().hashCode());
286
287 public void run() {
288
289 final String y = String.valueOf(new Object().hashCode());
290
291 class Sub {
292
293 final String z;
294
295 Sub(String z, int ignored) {
296 this(z, (float)ignored);
297 }
298
299 Sub(String z, float ignored) {
300 this.z = z;
301 }
302
303 Sub(String z, byte ignored) {
304 super();
305 this.z = z;
306 }
307
308 Sub(String z, char ignored) {
309 this(z, (int)ignored);
310 }
311
312 String x() {
313 return x;
314 }
315
316 String y() {
317 return y;
318 }
319
320 String z() {
321 return z;
322 }
323 }
324
325 final String z = String.valueOf(new Object().hashCode());
326
327 final Sub[] subs = new Sub[] {
328 new Sub(z, 1),
329 new Sub(z, -1),
330 new Sub(z, (float)0),
331 new Sub(z, (byte)0),
332 new Sub(z, (char)0)
333 };
334
335 for (int i = 0; i < subs.length; i++) {
336 //System.err.println("i = " + i);
337 final Sub sub = subs[i];
338 final String subx = sub.x();
339 final String suby = sub.y();
340 final String subz = sub.z();
341 if (!x.equals(subx))
342 throw new RuntimeException("x=" + x + " but sub[" + i + "].x()=" + subx);
343 if (!y.equals(suby))
344 throw new RuntimeException("y=" + y + " but sub[" + i + "].y()=" + suby);
345 if (!z.equals(subz))
346 throw new RuntimeException("z=" + z + " but sub[" + i + "].z()=" + subz);
347 }
348 }
349 }
350
351 // Records
352 public class Test17 {
353
354 record Rectangle(float length, float width) { }
355
356 record StringHolder(String string) {
357 StringHolder {
358 java.util.Objects.requireNonNull(string);
359 }
360 }
361
362 record ValueHolder(int value) {
363 ValueHolder(float x) {
364 if (Float.isNaN(x))
365 throw new IllegalArgumentException();
366 this((int)x);
367 }
368 }
369 }
370
371 // Exceptions thrown by initializer block
372 public static class Test18 extends AtomicReference<Object> {
373
374 {
375 if ((this.get().hashCode() % 3) == 0)
376 throw new MyException();
377 }
378
379 public Test18(Object obj) throws MyException {
380 super(obj);
381 }
382
383 public Test18(boolean fail) throws MyException {
384 Object obj;
385 for (obj = new Object(); true; obj = new Object()) {
386 if (((obj.hashCode() % 3) == 0) != fail)
387 continue;
388 break;
389 }
390 this(obj);
391 }
392
393 public static class MyException extends Exception {
394 }
395 }
396
397 // super()/this() within outer try block but inside inner class
398 public static class Test19 {
399 public Test19(int x) {
400 try {
401 new Test1(x) {
402 @Override
403 public int hashCode() {
404 return x ^ super.hashCode();
405 }
406 };
407 } catch (StackOverflowError e) {
408 // ignore
409 }
410 }
411 }
412
413 // we allow 'this' reference prior to super() for field assignments only
414 public static class Test20 {
415 private int x;
416 public Test20(short x) {
417 x = x;
418 super();
419 }
420 public Test20(int x) {
421 this.x = x;
422 super();
423 }
424 public Test20(char x) {
425 Test20.this.x = x;
426 super();
427 }
428 }
429
430 // allow creating and using local and anonymous classes before super()
431 // they will not have enclosing instances though
432 public static class Test21 {
433 public Test21(int x) {
434 Runnable r = new Runnable() {
435 public void run() {
436 this.hashCode();
437 }
438 };
439 r.run();
440 super();
441 r.run();
442 }
443 public Test21(float x) {
444 class Foo {
445 public void bar() {
446 this.hashCode();
447 }
448 };
449 new Foo().bar();
450 super();
451 new Foo().bar();
452 }
453 }
454
455 // Lambdas within constructors (JDK-8345438)
456 public static class Test22 {
457 public Test22() {
458 Runnable r = () -> System.out.println();
459 super();
460 r.run();
461 }
462 public Test22(int x) {
463 Runnable r = () -> System.out.println();
464 r.run();
465 super();
466 }
467 public Test22(char x) {
468 Runnable r = () -> {
469 class A {
470 A() {
471 return;
472 }
473 A(int x) {
474 Runnable r2 = () -> {
475 return;
476 };
477 this();
478 r2.run();
479 }
480 A(char x) {
481 this(0);
482 }
483 }
484 return;
485 };
486 r.run();
487 super();
488 }
489 }
490
491 // Receiver parameter syntax (JDK-8356551)
492 public static class Test23 {
493 public Test23() {
494 class Local {
495 Local(Test23 Test23.this) {
496 }
497 }
498 super();
499 new Local();
500 }
501 }
502
503 // Test for JDK-8349754
504 public static class Test24 {
505 private int i;
506 class Sub extends Test24 {
507 Sub() {
508 i = 3; // here "i" refers to "Test23.this.i", not "this.i" - so it's OK
509 super();
510 }
511 }
512 }
513
514 public static class Test25 {
515 public Test25(Object o) {}
516
517 class Sub extends Test25 {
518 public Sub() {
519 super(new Object() {
520 void foo() {
521 getClass();
522 }
523 });
524 }
525 }
526 }
527
528 public static void main(String[] args) {
529 new Test0();
530 new Test1();
531 new Test1(7);
532 new Test2<Byte>();
533 new Test2<>(args);
534 new Test3();
535 new SuperInitGood(3).new Test5(3);
536 new SuperInitGood(3).new Test6();
537 SuperInitGood.test7("foo");
538 SuperInitGood.test8();
539 new Test9(new SuperInitGood(5), "abc");
540 new Test10(7);
541 new Test11(9);
542 new Test12();
543 new Test13();
544 Test14 t14 = new Test14();
545 assert t14.x == 0 && t14.y == -1 && t14.z == 13;
546 t14 = new Test14(7);
547 assert t14.x == 7 && t14.y == -1 && t14.z == 13;
548 new Test15c(new Test15("foo"), "bar");
549 new Test16().run();
550 new Test17.StringHolder("foo");
551 try {
552 new Test17.StringHolder(null);
553 throw new Error();
554 } catch (NullPointerException e) {
555 // expected
556 }
557 try {
558 new Test18(true);
559 assert false : "expected exception";
560 } catch (Test18.MyException e) {
561 // expected
562 }
563 try {
564 new Test18(false);
565 } catch (Test18.MyException e) {
566 assert false : "unexpected exception: " + e;
567 }
568 new Test19(123);
569 new Test20(123);
570 new Test21((int)123);
571 new Test21((float)123);
572 new Test22('x');
573 new Test23();
574 new Test24();
575 new Test25(null);
576 }
577 }