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