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 
 25 /**
 26  * @test
 27  * @bug 8291360
 28  * @summary Test getting the class file version for java.lang.Class API
 29  * @modules java.base/java.lang:open
 30  * @compile classFileVersions.jcod
 31  * @compile --enable-preview -source ${jdk.version} ClassFileVersionTest.java
 32  * @run main/othervm --enable-preview ClassFileVersionTest
 33  */
 34 
 35 import java.lang.reflect.*;
 36 
 37 public class ClassFileVersionTest {
 38     public static final int LOWER_16 = 0x0000_FFFF;
 39     /*
 40      * Include a use of a preview API so that the minor class file
 41      * version of the class file for this class gets set during
 42      * compilation. If a particular class becomes non-preview, any
 43      * currently preview class can be substituted in.
 44      */
 45     private static final Class<?> PREVIEW_API = java.lang.ScopedValue.class;
 46     static Method m;
 47 
 48     public static void testIt(String className, int expectedResult) throws Exception {
 49         testIt(Class.forName(className), expectedResult);
 50     }
 51 
 52     public static void testIt(Class<?> testClass, int expectedResult) throws Exception {
 53         int ver = (int)m.invoke(testClass);
 54         if (ver != expectedResult) {
 55             int exp_minor = (expectedResult >> 16) & LOWER_16;
 56             int exp_major = expectedResult & LOWER_16;
 57             int got_minor = (ver >> 16) & LOWER_16;
 58             int got_major = ver & LOWER_16;
 59             throw new RuntimeException(
 60                 "Expected " + exp_minor + ":" + exp_major + " but got " + got_minor + ":" + got_major);
 61         }
 62     }
 63 
 64     public static void main(String argv[]) throws Throwable {
 65         Class<?> cl = java.lang.Class.class;
 66         m = cl.getDeclaredMethod("getClassFileVersion", new Class[0]);
 67         m.setAccessible(true);
 68 
 69         int latestMajor = ClassFileFormatVersion.latest().major();
 70 
 71         testIt(Object.class, latestMajor);
 72         // ClassFileVersionTest use preview features so its minor version should be 0xFFFF
 73         testIt(ClassFileVersionTest.class, (~LOWER_16) | latestMajor);
 74         testIt("Version64", 64);
 75         testIt("Version59", 59);
 76         testIt("Version45_3", 0x0003_002D);  // 3:45
 77 
 78         // test primitive array.  should return latest version.
 79         int ver = (int)m.invoke((new int[3]).getClass());
 80         if (ver != latestMajor) {
 81             int got_minor = (ver >> 16) & LOWER_16;
 82             int got_major = ver & LOWER_16;
 83             throw new RuntimeException(
 84                 "Expected 0:" + latestMajor + ", but got " + got_minor + ":" + got_major + " for primitive array");
 85         }
 86 
 87         // test object array.  should return class file version of component.
 88         ver = (int)m.invoke((new Version59[2]).getClass());
 89         if (ver != 59) {
 90             int got_minor = (ver >> 16) & LOWER_16;
 91             int got_major = ver & LOWER_16;
 92             throw new RuntimeException(
 93                 "Expected 0:59, but got " + got_minor + ":" + got_major + " for object array");
 94         }
 95 
 96         // test multi-dimensional object array.  should return class file version of component.
 97         ver = (int)m.invoke((new Version59[3][2]).getClass());
 98         if (ver != 59) {
 99             int got_minor = (ver >> 16) & LOWER_16;
100             int got_major = ver & LOWER_16;
101             throw new RuntimeException(
102                 "Expected 0:59, but got " + got_minor + ":" + got_major + " for object array");
103         }
104     }
105 }