/* * Copyright (c) 1999, 2020, 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. */ package java.lang.reflect; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import java.util.Objects; /** * {@code InvocationHandler} is the interface implemented by * the invocation handler of a proxy instance. * *
Each proxy instance has an associated invocation handler. * When a method is invoked on a proxy instance, the method * invocation is encoded and dispatched to the {@code invoke} * method of its invocation handler. * * @author Peter Jones * @see Proxy * @since 1.3 */ public interface InvocationHandler { /** * Processes a method invocation on a proxy instance and returns * the result. This method will be invoked on an invocation handler * when a method is invoked on a proxy instance that it is * associated with. * * @param proxy the proxy instance that the method was invoked on * * @param method the {@code Method} instance corresponding to * the interface method invoked on the proxy instance. The declaring * class of the {@code Method} object will be the interface that * the method was declared in, which may be a superinterface of the * proxy interface that the proxy class inherits the method through. * * @param args an array of objects containing the values of the * arguments passed in the method invocation on the proxy instance, * or {@code null} if interface method takes no arguments. * Arguments of primitive types are wrapped in instances of the * appropriate primitive wrapper class, such as * {@code java.lang.Integer} or {@code java.lang.Boolean}. * * @return the value to return from the method invocation on the * proxy instance. If the declared return type of the interface * method is a primitive type, then the value returned by * this method must be an instance of the corresponding primitive * wrapper class; otherwise, it must be a type assignable to the * declared return type. If the value returned by this method is * {@code null} and the interface method's return type is * primitive, then a {@code NullPointerException} will be * thrown by the method invocation on the proxy instance. If the * value returned by this method is otherwise not compatible with * the interface method's declared return type as described above, * a {@code ClassCastException} will be thrown by the method * invocation on the proxy instance. * * @throws Throwable the exception to throw from the method * invocation on the proxy instance. The exception's type must be * assignable either to any of the exception types declared in the * {@code throws} clause of the interface method or to the * unchecked exception types {@code java.lang.RuntimeException} * or {@code java.lang.Error}. If a checked exception is * thrown by this method that is not assignable to any of the * exception types declared in the {@code throws} clause of * the interface method, then an * {@link UndeclaredThrowableException} containing the * exception that was thrown by this method will be thrown by the * method invocation on the proxy instance. * * @see UndeclaredThrowableException */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; /** * Invokes the specified default method on the given {@code proxy} instance with * the given parameters. The given {@code method} must be a default method * declared in a proxy interface of the {@code proxy}'s class or inherited * from its superinterface directly or indirectly. *
* Invoking this method behaves as if {@code invokespecial} instruction executed * from the proxy class, targeting the default method in a proxy interface. * This is equivalent to the invocation: * {@code X.super.m(A* a)} where {@code X} is a proxy interface and the call to * {@code X.super::m(A*)} is resolved to the given {@code method}. *
* Examples: interface {@code A} and {@code B} both declare a default * implementation of method {@code m}. Interface {@code C} extends {@code A} * and inherits the default method {@code m} from its superinterface {@code A}. * *
* * The following creates a proxy instance that implements {@code A} * and invokes the default method {@code A::m}. * *{@code * interface A { * default T m(A a) { return t1; } * } * interface B { * default T m(A a) { return t2; } * } * interface C extends A {} * }
* * If a proxy instance implements both {@code A} and {@code B}, both * of which provides the default implementation of method {@code m}, * the invocation handler can dispatch the method invocation to * {@code A::m} or {@code B::m} via the {@code invokeDefault} method. * For example, the following code delegates the method invocation * to {@code B::m}. * *{@code * Object proxy = Proxy.newProxyInstance(loader, new Class>[] { A.class }, * (o, m, params) -> { * if (m.isDefault()) { * // if it's a default method, invoke it * return InvocationHandler.invokeDefault(o, m, params); * } * }); * }
* * If a proxy instance implements {@code C} that inherits the default * method {@code m} from its superinterface {@code A}, then * the interface method invocation on {@code "m"} is dispatched to * the invocation handler's {@link #invoke(Object, Method, Object[]) invoke} * method with the {@code Method} object argument representing the * default method {@code A::m}. * *{@code * Object proxy = Proxy.newProxyInstance(loader, new Class>[] { A.class, B.class }, * (o, m, params) -> { * if (m.getName().equals("m")) { * // invoke B::m instead of A::m * Method bMethod = B.class.getMethod(m.getName(), m.getParameterTypes()); * return InvocationHandler.invokeDefault(o, bMethod, params); * } * }); * }
* * The invocation of method {@code "m"} on this {@code proxy} will behave * as if {@code C.super::m} is called and that is resolved to invoking * {@code A::m}. *{@code * Object proxy = Proxy.newProxyInstance(loader, new Class>[] { C.class }, * (o, m, params) -> { * if (m.isDefault()) { * // behaves as if calling C.super.m(params) * return InvocationHandler.invokeDefault(o, m, params); * } * }); * }
* Adding a default method, or changing a method from abstract to default * may cause an exception if an existing code attempts to call {@code invokeDefault} * to invoke a default method. * * For example, if {@code C} is modified to implement a default method * {@code m}: * *
* * The code above that creates proxy instance {@code proxy} with * the modified {@code C} will run with no exception and it will result in * calling {@code C::m} instead of {@code A::m}. *{@code * interface C extends A { * default T m(A a) { return t3; } * } * }
* The following is another example that creates a proxy instance of {@code C} * and the invocation handler calls the {@code invokeDefault} method * to invoke {@code A::m}: * *
* * The above code runs successfully with the old version of {@code C} and * {@code A::m} is invoked. When running with the new version of {@code C}, * the above code will fail with {@code IllegalArgumentException} because * {@code C} overrides the implementation of the same method and * {@code A::m} is not accessible by a proxy instance. * * @apiNote * The {@code proxy} parameter is of type {@code Object} rather than {@code Proxy} * to make it easy for {@link InvocationHandler#invoke(Object, Method, Object[]) * InvocationHandler::invoke} implementation to call directly without the need * of casting. * * @param proxy the {@code Proxy} instance on which the default method to be invoked * @param method the {@code Method} instance corresponding to a default method * declared in a proxy interface of the proxy class or inherited * from its superinterface directly or indirectly * @param args the parameters used for the method invocation; can be {@code null} * if the number of formal parameters required by the method is zero. * @return the value returned from the method invocation * * @throws IllegalArgumentException if any of the following conditions is {@code true}: *{@code * C c = (C) Proxy.newProxyInstance(loader, new Class>[] { C.class }, * (o, m, params) -> { * if (m.getName().equals("m")) { * // IllegalArgumentException thrown as {@code A::m} is not a method * // inherited from its proxy interface C * Method aMethod = A.class.getMethod(m.getName(), m.getParameterTypes()); * return InvocationHandler.invokeDefault(o, aMethod params); * } * }); * c.m(...); * }