jdk.internal.reflect.AccessorUtils Maven / Gradle / Ivy
/*
* This code is based on OpenJDK source file(s) which contain the following copyright notice:
*
* ------
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
* ------
*
* This file may contain additional modifications which are Copyright (c) Red Hat and other
* contributors.
*/
package jdk.internal.reflect;
import java.lang.invoke.WrongMethodTypeException;
import java.util.Set;
import org.qbicc.rt.annotation.Tracking;
/**
* Utility methods used by DirectMethodHandleAccessor and DirectConstructorHandleAccessor
*/
// This is a backport of OpenJDK 18 MethodHandle based reflection to JDK17 for Qbicc.
// It should be removed when we update to the next LTS version of Java.
@Tracking("src/java.base/share/classes/jdk/internal/reflect/AccessorUtils.java")
public class AccessorUtils {
/**
* Determines if the given exception thrown by MethodHandle::invokeExact
* is caused by an illegal argument passed to Method::invoke or
* Constructor::newInstance. This method inspects the stack trace of
* the exception to detect if it is thrown by the method handle core
* implementation or the implementation of the reflected method or constructor.
*
* MethodHandle::invoke throws ClassCastException if the receiver object
* is not an instance of the declaring class of the method if the method
* is an instance method, or if a parameter value cannot be converted
* to the corresponding formal parameter type. It throws
* NullPointerException if the receiver object is null if the method
* is an instance method, or if unboxing operation of a parameter fails
* because the parameter value is null. It throws WrongMethodTypeException
* if the method type mismatches.
*
* @param accessorType the accessor class that does the method handle invocation
* @param e ClassCastException, NullPointerException or WrongMethodTypeException
*/
static boolean isIllegalArgument(Class> accessorType, RuntimeException e) {
assert(e instanceof ClassCastException || e instanceof NullPointerException ||
e instanceof WrongMethodTypeException);
StackTraceElement[] stackTrace = e.getStackTrace();
if (stackTrace.length == 0) {
return false; // would this happen?
}
int i = 0;
StackTraceElement frame = stackTrace[0];
// Class::cast and Objects::requiresNonNull may be thrown by the implementation
// of the reflected method/constructor. Skip them and continue.
if ((frame.getClassName().equals("java.lang.Class") && frame.getMethodName().equals("cast"))
|| (frame.getClassName().equals("java.util.Objects") && frame.getMethodName().equals("requiresNonNull"))) {
i++;
}
for (; i < stackTrace.length; i++) {
frame = stackTrace[i];
String cname = frame.getClassName();
// it's illegal argument if this exception is thrown from accessorType
if (cname.equals(accessorType.getName())) {
return true;
}
// if this exception is thrown from an unnamed module or not from java.base
// then i.e. not from method handle core implementation
if (frame.getModuleName() == null || !frame.getModuleName().equals("java.base")) {
return false;
}
int index = cname.lastIndexOf(".");
String pn = index > 0 ? cname.substring(0, index) : "";
// exception thrown from java.base but not from core reflection/method handle internals
if (!IMPL_PACKAGES.contains(pn)) {
return false;
}
// If Constructor::newInstance is invoked by Method::invoke or vice versa,
// so the exception is thrown from the implementation body of the reflected
// method or constructor
if ((accessorType == DirectMethodHandleAccessor.class
&& cname.startsWith(DirectConstructorHandleAccessor.class.getName()))
|| (accessorType == DirectConstructorHandleAccessor.class
&& cname.startsWith(DirectMethodHandleAccessor.class.getName()))) {
// thrown from another reflection accessor impl class
return false;
}
}
return false;
}
private static final Set IMPL_PACKAGES = Set.of(
"java.lang.reflect",
"java.lang.invoke",
"jdk.internal.reflect",
"sun.invoke.util"
);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy