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 }