1 /*
  2  * Copyright (c) 2012, 2021, 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.MethodHandles.Lookup;
 31 
 32 /*
 33  * Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public.
 34  */
 35 /*non-public*/
 36 final class InfoFromMemberName implements MethodHandleInfo {
 37     private final MemberName member;
 38     private final int referenceKind;
 39 
 40     InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) {
 41         assert(member.isResolved() || member.isMethodHandleInvoke() || member.isVarHandleMethodInvoke());
 42         assert(member.referenceKindIsConsistentWith(referenceKind));
 43         this.member = member;
 44         this.referenceKind = referenceKind;
 45     }
 46 
 47     @Override
 48     public Class<?> getDeclaringClass() {
 49         return member.getDeclaringClass();
 50     }
 51 
 52     @Override
 53     public String getName() {
 54         return member.getName();
 55     }
 56 
 57     @Override
 58     public MethodType getMethodType() {
 59         return member.getMethodOrFieldType();
 60     }
 61 
 62     @Override
 63     public int getModifiers() {
 64         return member.getModifiers();
 65     }
 66 
 67     @Override
 68     public int getReferenceKind() {
 69         return referenceKind;
 70     }
 71 
 72     @Override
 73     public String toString() {
 74         return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
 75     }
 76 
 77     @Override
 78     public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
 79         if ((member.isMethodHandleInvoke() || member.isVarHandleMethodInvoke())
 80             && !member.isVarargs()) {
 81             // This member is an instance of a signature-polymorphic method, which cannot be reflected
 82             // A method handle invoker can come in either of two forms:
 83             // A generic placeholder (present in the source code, and varargs)
 84             // and a signature-polymorphic instance (synthetic and not varargs).
 85             // For more information see comments on {@link MethodHandleNatives#linkMethod}.
 86             throw new IllegalArgumentException("cannot reflect signature polymorphic method");
 87         }
 88         @SuppressWarnings("removal")
 89         Member mem = AccessController.doPrivileged(new PrivilegedAction<>() {
 90                 public Member run() {
 91                     try {
 92                         return reflectUnchecked();
 93                     } catch (ReflectiveOperationException ex) {
 94                         throw new IllegalArgumentException(ex);
 95                     }
 96                 }
 97             });
 98         try {
 99             Class<?> defc = getDeclaringClass();
100             byte refKind = (byte) getReferenceKind();
101             lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
102         } catch (IllegalAccessException ex) {
103             throw new IllegalArgumentException(ex);
104         }
105         return expected.cast(mem);
106     }
107 
108     private Member reflectUnchecked() throws ReflectiveOperationException {
109         byte refKind = (byte) getReferenceKind();
110         Class<?> defc = getDeclaringClass();
111         boolean isPublic = Modifier.isPublic(getModifiers());
112         if (member.isObjectConstructorOrStaticInitMethod()) {
113             MethodType methodType = getMethodType();
114             if (MethodHandleNatives.refKindIsObjectConstructor(refKind) &&
115                 methodType.returnType() != void.class) {
116                 // object constructor
117                 throw new IllegalArgumentException("object constructor must be of void return type");
118             } else if (MethodHandleNatives.refKindIsMethod(refKind) &&
119                        methodType.returnType() != defc.asValueType()) {
120                 // TODO: allow to return Object or perhaps one of the supertypes of that class
121                 // static init factory
122                 throw new IllegalArgumentException("static constructor must be of " + defc.getName());
123             }
124 
125             return isPublic ? defc.getConstructor(methodType.parameterArray())
126                             : defc.getDeclaredConstructor(methodType.parameterArray());
127         } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
128             if (isPublic)
129                 return defc.getMethod(getName(), getMethodType().parameterArray());
130             else
131                 return defc.getDeclaredMethod(getName(), getMethodType().parameterArray());
132         } else if (MethodHandleNatives.refKindIsField(refKind)) {
133             if (isPublic)
134                 return defc.getField(getName());
135             else
136                 return defc.getDeclaredField(getName());
137         } else {
138             throw new IllegalArgumentException("referenceKind="+refKind);
139         }
140     }
141 
142     private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
143         if (mem instanceof Method) {
144             boolean wantSpecial = (refKind == REF_invokeSpecial);
145             return new MemberName((Method) mem, wantSpecial);
146         } else if (mem instanceof Constructor) {
147             return new MemberName((Constructor) mem);
148         } else if (mem instanceof Field) {
149             boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
150             return new MemberName((Field) mem, isSetter);
151         }
152         throw new InternalError(mem.getClass().getName());
153     }
154 }