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