1 /*
  2  * Copyright (c) 2025, 2026, 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 that isValue and modifiers return correct results for value classes & arrays
 27  * @library /test/lib
 28  * @enablePreview false
 29  * @modules java.base/jdk.internal.misc
 30  *          java.base/jdk.internal.value
 31  * @run junit/othervm IdentityReflectionTest
 32  * @run junit/othervm --enable-preview IdentityReflectionTest
 33  */
 34 
 35 import org.junit.jupiter.api.Test;
 36 
 37 import java.lang.classfile.ClassFile;
 38 import java.lang.reflect.AccessFlag;
 39 import java.lang.reflect.Modifier;
 40 import java.util.Set;
 41 
 42 import jdk.internal.misc.PreviewFeatures;
 43 
 44 import static jdk.test.lib.Asserts.*;
 45 
 46 public class IdentityReflectionTest {
 47 
 48     static final boolean PREVIEW = PreviewFeatures.isEnabled();
 49 
 50     static final Class<?>[] valueClasses = {
 51         Number.class,
 52         Record.class,
 53 
 54         Byte.class,
 55         Short.class,
 56         Integer.class,
 57         Long.class,
 58         Float.class,
 59         Double.class,
 60         Boolean.class,
 61         Character.class,
 62 
 63         java.util.Optional.class,
 64         java.util.OptionalDouble.class,
 65         java.util.OptionalInt.class,
 66         java.util.OptionalLong.class,
 67 
 68         java.time.Duration.class,
 69         java.time.Instant.class,
 70         java.time.LocalDate.class,
 71         java.time.LocalDateTime.class,
 72         java.time.LocalTime.class,
 73         java.time.MonthDay.class,
 74         java.time.OffsetDateTime.class,
 75         java.time.OffsetTime.class,
 76         java.time.Period.class,
 77         java.time.Year.class,
 78         java.time.YearMonth.class,
 79         java.time.ZonedDateTime.class,
 80 
 81         java.time.chrono.HijrahDate.class,
 82         java.time.chrono.JapaneseDate.class,
 83         java.time.chrono.MinguoDate.class,
 84         java.time.chrono.ThaiBuddhistDate.class,
 85     };
 86 
 87     static final Class<?>[] identityClasses = {
 88         Object.class,
 89         String.class,
 90         Thread.class,
 91         java.math.BigInteger.class,
 92         java.math.BigDecimal.class,
 93         Integer[].class,
 94         Thread[].class,
 95     };
 96 
 97     @Test
 98     void testIsValue() {
 99         checkIsValue(int.class, false);
100         checkIsValue(Runnable.class, false);
101         for (Class<?> c : valueClasses) {
102             checkIsValue(c, PREVIEW);
103         }
104         for (Class<?> c : identityClasses) {
105             checkIsValue(c, false);
106         }
107     }
108 
109     @SuppressWarnings("preview")
110     void checkIsValue(Class<?> c, boolean expected) {
111         assertEquals(expected, c.isValue(),
112                       c + " " + (expected ? "is" : "is not") + " a value class");
113     }
114 
115     @Test
116     void testModifiers() {
117         checkIdentityModifier(int.class, false);
118         checkIdentityModifier(Runnable.class, false);
119         for (Class<?> c : valueClasses) {
120             checkIdentityModifier(c, false);
121         }
122         for (Class<?> c : identityClasses) {
123             checkIdentityModifier(c, PREVIEW);
124         }
125     }
126 
127     @SuppressWarnings("preview")
128     void checkIdentityModifier(Class<?> c, boolean expected) {
129         int mod = c.getModifiers();
130         assertEquals(expected, (mod & ClassFile.ACC_IDENTITY) != 0,
131             "Modifier of " + c + " (" + Integer.toHexString(mod) + ") " +
132             (expected ? "should" : "should not") + " have ACC_IDENTITY set");
133     }
134 
135     @Test
136     void testAccessFlags() {
137         checkIdentityAccessFlag(int.class, false);
138         checkIdentityAccessFlag(Runnable.class, false);
139         for (Class<?> c : valueClasses) {
140             checkIdentityAccessFlag(c, false);
141         }
142         for (Class<?> c : identityClasses) {
143             checkIdentityAccessFlag(c, PREVIEW);
144         }
145     }
146 
147     @SuppressWarnings("preview")
148     void checkIdentityAccessFlag(Class<?> c, boolean expected) {
149         Set<AccessFlag> acc = c.accessFlags();
150         assertEquals(expected, acc.contains(AccessFlag.IDENTITY),
151             "Access flags of " + c + " (" + acc + ") " +
152             (expected ? "should" : "should not") + " contain IDENTITY");
153     }
154 }