1 /* 2 * Copyright (c) 2023, 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 import jdk.test.lib.Asserts; 25 import java.lang.reflect.Method; 26 import java.lang.reflect.Field; 27 import jdk.internal.misc.Unsafe; 28 import jdk.internal.vm.annotation.NullRestricted; 29 import jdk.internal.vm.annotation.ImplicitlyConstructible; 30 import jdk.internal.vm.annotation.LooselyConsistentValue; 31 32 33 34 /* 35 * @test 36 * @summary Test of ImplicitlyConstructible, NullRestricted and LooselyConsistentValue annotations 37 * @modules java.base/jdk.internal.misc 38 * java.base/jdk.internal.vm.annotation 39 * @library /test/lib 40 * @enablePreview 41 * @compile AnnotationsTests.java 42 * @run main/othervm AnnotationsTests 43 */ 44 45 46 public class AnnotationsTests { 47 48 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 49 50 public static void main(String[] args) { 51 AnnotationsTests tests = new AnnotationsTests(); 52 Class c = tests.getClass(); 53 for (Method m : c.getDeclaredMethods()) { 54 if (m.getName().startsWith("test_")) { 55 try { 56 System.out.println("Running " + m.getName()); 57 m.invoke(tests); 58 } catch (Throwable t) { 59 t.printStackTrace(); 60 throw new RuntimeException(t); 61 } 62 } 63 } 64 } 65 66 static class BadClass0 { 67 @NullRestricted 68 String s; 69 } 70 71 // Test detection of illegal usage of NullRestricted on an identity field 72 void test_0() { 73 Throwable exception = null; 74 try { 75 BadClass0 bc = new BadClass0(); 76 } catch (IncompatibleClassChangeError e) { 77 exception = e; 78 System.out.println("Received " + e); 79 } 80 Asserts.assertNotNull(exception, "Failed to detect illegal use of @NullRestricted"); 81 } 82 83 // Test detection of mismatch between a @NullRestricted field and its class that is not @ImplicitlyConstructible 84 static value class ValueClass1 { 85 int i = 0; 86 int j = 0; 87 } 88 89 static class BadClass1 { 90 @NullRestricted 91 ValueClass1 vc; 92 } 93 94 void test_1() { 95 Throwable exception = null; 96 try { 97 BadClass1 tc = new BadClass1(); 98 } catch (IncompatibleClassChangeError e) { 99 exception = e; 100 System.out.println("Received " + e); 101 } 102 Asserts.assertNotNull(exception, "Failed to detect illegal use of @NullRestricted"); 103 } 104 105 // Test a valid @NullRestricted field with a class that is @ImplicitlyConstructible 106 @ImplicitlyConstructible 107 static value class ValueClass2 { 108 int i = 0; 109 int j = 0; 110 } 111 112 static class GoodClass2 { 113 @NullRestricted 114 ValueClass2 vc; 115 } 116 117 void test_2() { 118 Throwable exception = null; 119 try { 120 GoodClass2 tc = new GoodClass2(); 121 } catch (IncompatibleClassChangeError e) { 122 exception = e; 123 System.out.println("Received " + e); 124 } 125 Asserts.assertNull(exception, "Unexpected exception: " + exception); 126 } 127 128 // Invalid usage of @ImplicitlyConstructible on an identity class 129 @ImplicitlyConstructible 130 static class BadClass3 { 131 132 } 133 134 void test_3() { 135 Throwable exception = null; 136 try { 137 BadClass3 tc = new BadClass3(); 138 } catch (ClassFormatError e) { 139 exception = e; 140 System.out.println("Received " + e); 141 } 142 Asserts.assertNotNull(exception, "Failed to detect illegal use of @ImplicitlyConstructible"); 143 } 144 145 // Test invalid usage of @LooselyConsistentValue on an identity class 146 @LooselyConsistentValue 147 static class BadClass4 { 148 149 } 150 151 void test_4() { 152 Throwable exception = null; 153 try { 154 BadClass4 tc = new BadClass4(); 155 } catch (ClassFormatError e) { 156 exception = e; 157 System.out.println("Received " + e); 158 } 159 Asserts.assertNotNull(exception, "Failed to detect illegal use of @LooselyConsistentValue"); 160 } 161 162 // Test field flattening of @NullRestricted annotated fields 163 164 @ImplicitlyConstructible 165 static value class ValueClass5 { 166 int i = 0; 167 } 168 169 static class GoodClass5 { 170 ValueClass5 f0 = new ValueClass5(); 171 172 @NullRestricted 173 ValueClass5 f1 = new ValueClass5(); 174 } 175 176 void test_5() { 177 Throwable exception = null; 178 try { 179 GoodClass5 vc = new GoodClass5(); 180 Field f0 = vc.getClass().getDeclaredField("f0"); 181 Asserts.assertFalse(UNSAFE.isFlatField(f0), "Unexpected flat field"); 182 Field f1 = vc.getClass().getDeclaredField("f1"); 183 Asserts.assertTrue(UNSAFE.isFlatField(f1), "Flat field expected, but field is not flat"); 184 } catch (IncompatibleClassChangeError e) { 185 exception = e; 186 System.out.println("Received " + e); 187 } catch(NoSuchFieldException e) { 188 Asserts.fail("Test error"); 189 } 190 Asserts.assertNull(exception, "Unexpected exception: " + exception); 191 } 192 193 194 // Test detection/handling of circularity 195 196 @ImplicitlyConstructible 197 static value class ValueClass6a { 198 @NullRestricted 199 ValueClass6b val = new ValueClass6b(); 200 } 201 202 @ImplicitlyConstructible 203 static value class ValueClass6b { 204 @NullRestricted 205 ValueClass6a val = new ValueClass6a(); 206 } 207 208 static class BadClass6 { 209 @NullRestricted 210 ValueClass6a val = new ValueClass6a(); 211 } 212 213 void test_6() { 214 Throwable exception = null; 215 try { 216 BadClass6 bc = new BadClass6(); 217 } catch (ClassCircularityError e) { 218 exception = e; 219 System.out.println("Received " + e); 220 } 221 Asserts.assertNotNull(exception, "Failed to detect circularity"); 222 } 223 224 // Test null restricted static field 225 @ImplicitlyConstructible 226 static value class ValueClass7 { 227 int i = 0; 228 } 229 230 static class GoodClass7 { 231 @NullRestricted 232 static ValueClass7 sval; 233 } 234 235 void test_7() { 236 Throwable exception = null; 237 try { 238 ValueClass7 val = GoodClass7.sval; 239 Asserts.assertNotNull(val, "Unexpected null value"); 240 } catch (Throwable e) { 241 exception = e; 242 System.out.println("Received " + e); 243 } 244 Asserts.assertNull(exception, "Unexpected exception: " + exception); 245 } 246 247 // Test circularity on static fields 248 @ImplicitlyConstructible 249 static value class ValueClass8 { 250 @NullRestricted 251 static ValueClass8 sval; 252 } 253 254 void test_8() { 255 Throwable exception = null; 256 try { 257 ValueClass8 val = ValueClass8.sval; 258 Asserts.assertNotNull(val, "Unexpected null value"); 259 } catch (Throwable e) { 260 exception = e; 261 System.out.println("Received " + e); 262 } 263 Asserts.assertNull(exception, "Unexpected exception: " + exception); 264 } 265 266 // Test that writing null to a @NullRestricted non-static field throws an exception 267 @ImplicitlyConstructible 268 static value class ValueClass9 { 269 int i = 0; 270 } 271 272 static class GoodClass9 { 273 @NullRestricted 274 ValueClass9 val = new ValueClass9(); 275 } 276 277 void test_9() { 278 Throwable exception = null; 279 try { 280 GoodClass9 gc = new GoodClass9(); 281 gc.val = null; 282 } catch(NullPointerException e) { 283 exception = e; 284 System.out.println("Received " + e); 285 } 286 Asserts.assertNotNull(exception, "Expected NullPointerException not received"); 287 } 288 289 // Test that writing null to a @NullRestricted static field throws an exception 290 @ImplicitlyConstructible 291 static value class ValueClass10 { 292 @NullRestricted 293 static ValueClass10 sval; 294 } 295 296 void test_10() { 297 Throwable exception = null; 298 try { 299 ValueClass10.sval = null; 300 } catch(NullPointerException e) { 301 exception = e; 302 System.out.println("Received " + e); 303 } 304 Asserts.assertNotNull(exception, "Expected NullPointerException not received"); 305 } 306 307 // Test uninitialized static null restricted field with a class not implicitly constructible 308 static value class ValueClass11 { 309 int i = 0; 310 int j = 0; 311 } 312 313 static class BadClass11 { 314 @NullRestricted 315 static ValueClass11 val; 316 } 317 318 void test_11() { 319 Throwable exception = null; 320 try { 321 ValueClass11 val = BadClass11.val; 322 System.out.println(val); 323 } catch(IncompatibleClassChangeError e) { 324 exception = e; 325 System.out.println("Received " + e); 326 } 327 Asserts.assertNotNull(exception, "Expected IncompatibleClassChangerError not received"); 328 } 329 330 // Test illegal use of @NullRestricted on a primitive field 331 static class BadClass12 { 332 @NullRestricted 333 int i; 334 } 335 void test_12() { 336 Throwable exception = null; 337 try { 338 BadClass12 val = new BadClass12(); 339 System.out.println(val); 340 } catch(ClassFormatError e) { 341 exception = e; 342 System.out.println("Received " + e); 343 } 344 Asserts.assertNotNull(exception, "Expected ClassFormatError not received"); 345 } 346 347 // Test illegal use of @NullRestricted on an array field 348 static class BadClass13 { 349 @NullRestricted 350 int Integer[]; 351 } 352 void test_13() { 353 Throwable exception = null; 354 try { 355 BadClass13 val = new BadClass13(); 356 System.out.println(val); 357 } catch(ClassFormatError e) { 358 exception = e; 359 System.out.println("Received " + e); 360 } 361 Asserts.assertNotNull(exception, "Expected ClassFormatError not received"); 362 } 363 364 } 365