1 /*
2  * Copyright (c) 2012, 2013, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.lang.invoke;
27 
28 import java.security.*;
29 import java.lang.reflect.*;
30 import java.lang.invoke.MethodHandleNatives.Constants;
31 import java.lang.invoke.MethodHandles.Lookup;
32 import static java.lang.invoke.MethodHandleStatics.*;
33 
34 /*
35  * Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public.
36  */
37 /*non-public*/
38 final
39 class InfoFromMemberName implements MethodHandleInfo {
40     private final MemberName member;
41     private final int referenceKind;
42 
InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind)43     InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) {
44         assert(member.isResolved() || member.isMethodHandleInvoke() || member.isVarHandleMethodInvoke());
45         assert(member.referenceKindIsConsistentWith(referenceKind));
46         this.member = member;
47         this.referenceKind = referenceKind;
48     }
49 
50     @Override
getDeclaringClass()51     public Class<?> getDeclaringClass() {
52         return member.getDeclaringClass();
53     }
54 
55     @Override
getName()56     public String getName() {
57         return member.getName();
58     }
59 
60     @Override
getMethodType()61     public MethodType getMethodType() {
62         return member.getMethodOrFieldType();
63     }
64 
65     @Override
getModifiers()66     public int getModifiers() {
67         return member.getModifiers();
68     }
69 
70     @Override
getReferenceKind()71     public int getReferenceKind() {
72         return referenceKind;
73     }
74 
75     @Override
toString()76     public String toString() {
77         return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
78     }
79 
80     @Override
reflectAs(Class<T> expected, Lookup lookup)81     public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
82         if ((member.isMethodHandleInvoke() || member.isVarHandleMethodInvoke())
83             && !member.isVarargs()) {
84             // This member is an instance of a signature-polymorphic method, which cannot be reflected
85             // A method handle invoker can come in either of two forms:
86             // A generic placeholder (present in the source code, and varargs)
87             // and a signature-polymorphic instance (synthetic and not varargs).
88             // For more information see comments on {@link MethodHandleNatives#linkMethod}.
89             throw new IllegalArgumentException("cannot reflect signature polymorphic method");
90         }
91         Member mem = AccessController.doPrivileged(new PrivilegedAction<>() {
92                 public Member run() {
93                     try {
94                         return reflectUnchecked();
95                     } catch (ReflectiveOperationException ex) {
96                         throw new IllegalArgumentException(ex);
97                     }
98                 }
99             });
100         try {
101             Class<?> defc = getDeclaringClass();
102             byte refKind = (byte) getReferenceKind();
103             lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
104         } catch (IllegalAccessException ex) {
105             throw new IllegalArgumentException(ex);
106         }
107         return expected.cast(mem);
108     }
109 
reflectUnchecked()110     private Member reflectUnchecked() throws ReflectiveOperationException {
111         byte refKind = (byte) getReferenceKind();
112         Class<?> defc = getDeclaringClass();
113         boolean isPublic = Modifier.isPublic(getModifiers());
114         if (MethodHandleNatives.refKindIsMethod(refKind)) {
115             if (isPublic)
116                 return defc.getMethod(getName(), getMethodType().parameterArray());
117             else
118                 return defc.getDeclaredMethod(getName(), getMethodType().parameterArray());
119         } else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
120             if (isPublic)
121                 return defc.getConstructor(getMethodType().parameterArray());
122             else
123                 return defc.getDeclaredConstructor(getMethodType().parameterArray());
124         } else if (MethodHandleNatives.refKindIsField(refKind)) {
125             if (isPublic)
126                 return defc.getField(getName());
127             else
128                 return defc.getDeclaredField(getName());
129         } else {
130             throw new IllegalArgumentException("referenceKind="+refKind);
131         }
132     }
133 
convertToMemberName(byte refKind, Member mem)134     private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
135         if (mem instanceof Method) {
136             boolean wantSpecial = (refKind == REF_invokeSpecial);
137             return new MemberName((Method) mem, wantSpecial);
138         } else if (mem instanceof Constructor) {
139             return new MemberName((Constructor) mem);
140         } else if (mem instanceof Field) {
141             boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
142             return new MemberName((Field) mem, isSetter);
143         }
144         throw new InternalError(mem.getClass().getName());
145     }
146 }
147