1 /*
  2  * Copyright (c) 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 /*
 25  * @test
 26  * @summary test validation of value classes
 27  * @enablePreview
 28  * @compile cfpValueClassValidation.jcod
 29  * @run main/othervm -Xverify:remote ValueClassValidation
 30  */
 31 
 32 import javax.management.RuntimeErrorException;
 33 
 34 public class ValueClassValidation {
 35   public static void runTest(String test_name, String cfe_message, String icce_message) throws Exception {
 36     System.out.println("Testing: " + test_name);
 37     boolean gotException = false;
 38     try {
 39         Class newClass = Class.forName(test_name);
 40     } catch (java.lang.ClassFormatError e) {
 41       gotException = true;
 42       if (cfe_message != null) {
 43         if (!e.getMessage().contains(cfe_message)) {
 44             throw new RuntimeException( "Wrong ClassFormatError: " + e.getMessage());
 45         }
 46       } else {
 47         throw new RuntimeException( "Unexpected ClassFormatError: " + e.getMessage());
 48       }
 49     } catch (java.lang.IncompatibleClassChangeError e) {
 50       gotException = true;
 51       if (icce_message != null) {
 52         if (!e.getMessage().contains(icce_message)) {
 53             throw new RuntimeException( "Wrong IncompatibleClassChangeError: " + e.getMessage());
 54         }
 55       } else {
 56         throw new RuntimeException( "Unexpected IncompatibleClassChangeError: " + e.getMessage());
 57       }
 58     }
 59     if (!gotException) {
 60       if (cfe_message != null) {
 61         throw new RuntimeException("Missing ClassFormatError in test" + test_name);
 62       } else if (icce_message != null) {
 63         throw new RuntimeException("Missing IncompatibleClassChangeError in test" + test_name);
 64       }
 65     }
 66   }
 67 
 68   public static void main(String[] args) throws Exception {
 69 
 70     // Test none of ACC_ABSTRACT, ACC_FINAL or ACC_IDENTITY is illegal.
 71     runTest("InvalidClassFlags", "Illegal class modifiers in class InvalidClassFlags", null);
 72 
 73     // Test ACC_ABSTRACT without ACC_IDENTITY is legal
 74     runTest("AbstractValue", null, null);
 75 
 76     // Test ACC_FINAL without ACC_IDENTITY is legal
 77     runTest("FinalValue", null, null);
 78 
 79     // Test a concrete value class extending an abstract identity class
 80     runTest("ValueClass", null, "Value type ValueClass has an identity type as supertype");
 81 
 82     // Test a concrete identity class without ACC_IDENTITY but with an older class file version, extending an abstract identity class
 83     // (Test that the VM fixes missing ACC_IDENTITY in old class files)
 84     runTest("IdentityClass", null, null);
 85 
 86     // Test a concrete value class extending a concrete (i.e. final) value class
 87     runTest("ValueClass2", null, "class ValueClass2 cannot inherit from final class FinalValue");
 88 
 89     // Test an abstract value class extending an abstract identity class
 90     runTest("AbstractValueClass2", null, "Value type AbstractValueClass2 has an identity type as supertype");
 91 
 92     // Test an abstract identity class without ACC_IDENTITY but with an older class file version, extending an abstract identity class
 93     // (Test that the VM fixes missing ACC_IDENTITY in old class files)
 94     runTest("AbstractIdentityClass2", null, null);
 95 
 96     // Test an abstract value class extending a concrete (i.e. final) value class
 97     runTest("AbstractValueClass3", null, "class AbstractValueClass3 cannot inherit from final class FinalValue");
 98 
 99     //Test a concrete class without ACC_IDENTITY but with an older class file version, declaring a field without ACC_STATIC nor ACC_STRICT
100     // (Test that the VM fixes missing ACC_IDENTITY in old class files)
101     runTest("NotStaticNotStrictInOldClass", null, null);
102 
103     // Test a concrete value class with a static synchronized method
104     runTest("StaticSynchMethod", null, null);
105 
106     // Test a concrete value class with a non-static synchronized method
107     runTest("SynchMethod", "Method m in class SynchMethod (not an identity class) has illegal modifiers: 0x21", null);
108 
109     // Test an abstract value class with a static synchronized method
110     runTest("StaticSynchMethodInAbstractValue", null, null);
111 
112     // Test an abstract value class with a non-static synchronized method
113     runTest("SynchMethodInAbstractValue", "Method m in class SynchMethodInAbstractValue (not an identity class) has illegal modifiers: 0x21", null);
114 
115     // Test a class with a primitive descriptor in its LoadableDescriptors attribute:
116     runTest("PrimitiveInLoadableDescriptors", null, null);
117   }
118 }