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