1 /*
2 * Copyright (c) 2025, 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.incubator.code.dialect.java.FieldRef;
25 import jdk.incubator.code.dialect.java.JavaType;
26 import org.junit.jupiter.api.Test;
27
28 import java.lang.constant.ClassDesc;
29 import java.lang.invoke.MethodHandles;
30 import java.lang.invoke.MethodHandles.Lookup;
31 import java.lang.invoke.VarHandle;
32 import java.lang.invoke.VarHandle.VarHandleDesc;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.Modifier;
35
36 import static org.junit.jupiter.api.Assertions.assertEquals;
37 import static org.junit.jupiter.api.Assertions.assertThrows;
38
39 /*
40 * @test
41 * @modules jdk.incubator.code
42 * @modules java.base/java.lang.invoke:open
43 * @run junit TestFieldResolution
44 */
45 public class TestFieldResolution {
46 public static class C {
47 public static int s_x;
48 public int x;
49 long y;
50 static long s_y;
51 }
52
53 public static class C_Sub extends C { }
54
55 @Test
56 public void testClassDeclaredFieldsPrivateLookup() throws ReflectiveOperationException {
57 lookupInternal(C.class, C.class, MethodHandles.lookup());
58 }
59
60 @Test
61 public void testClassDeclaredFieldsPublicLookup() throws ReflectiveOperationException {
62 lookupInternal(C.class, C.class, publicLookup());
63 }
64
65 @Test
66 public void testClassInheritedFieldsPrivateLookup() throws ReflectiveOperationException {
67 lookupInternal(C_Sub.class, C.class, MethodHandles.lookup());
68 }
69
70 @Test
71 public void testClassInheritedFieldsPublicLookup() throws ReflectiveOperationException {
72 lookupInternal(C_Sub.class, C.class, publicLookup());
73 }
74
75 public interface I {
76 int X = 42;
77 }
78
79 public interface I_Sub extends I { }
80
81 public static class CI_Sub implements I_Sub { }
82
83 @Test
84 public void testInterfaceDeclaredFieldsPublicLookup() throws ReflectiveOperationException {
85 lookupInternal(I.class, I.class, publicLookup());
86 }
87
88 @Test
89 public void testInterfaceInheritedFieldsPublicLookup() throws ReflectiveOperationException {
90 lookupInternal(I_Sub.class, I.class, publicLookup());
91 }
92
93 @Test
94 public void testClassInterfaceInheritedFieldsPublicLookup() throws ReflectiveOperationException {
95 lookupInternal(CI_Sub.class, I.class, publicLookup());
96 }
97
98 static void lookupInternal(Class<?> refC, Class<?> cl, MethodHandles.Lookup lookup) throws ReflectiveOperationException {
99 for (Field f : cl.getDeclaredFields()) {
100 FieldRef fieldRef = FieldRef.field(refC, f.getName(), f.getType());
101 if (Modifier.isPublic(f.getModifiers()) || (lookup.lookupModes() & Lookup.ORIGINAL) != 0) {
102 Field resolvedF = fieldRef.resolveToField(lookup);
103 assertEquals(f, resolvedF);
104 VarHandle resolvedVH = fieldRef.resolveToHandle(lookup);
105 try {
106 VarHandleDesc vhDesc = resolvedVH.describeConstable().get();
107 FieldRef vhRef = FieldRef.field(
108 JavaType.type(varHandleDescDeclaringClass(vhDesc)),
109 vhDesc.constantName(),
110 JavaType.type(vhDesc.varType()));
111 assertEquals(vhRef.resolveToField(lookup), f);
112 } catch (InternalError ex) {
113 // @@@: this is a workaround -- there seems to be an issue with describeConstable for some VHs
114 }
115 } else {
116 assertThrows(ReflectiveOperationException.class, () -> fieldRef.resolveToField(lookup));
117 }
118 }
119 }
120
121 static MethodHandles.Lookup publicLookup() {
122 return MethodHandles.publicLookup().in(TestFieldResolution.class);
123 }
124
125 static ClassDesc varHandleDescDeclaringClass(VarHandleDesc varHandleDesc) throws ReflectiveOperationException {
126 Field f = VarHandleDesc.class.getDeclaredField("declaringClass");
127 f.setAccessible(true);
128 return (ClassDesc) f.get(varHandleDesc);
129 }
130 }