| /* GENERATED SOURCE. DO NOT MODIFY. */ |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.okhttp.internal; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| |
| /** |
| * Duck-typing for methods: Represents a method that may or may not be present on an object. |
| * |
| * @param <T> the type of the object the method might be on, typically an interface or base class |
| */ |
| class OptionalMethod<T> { |
| |
| /** The return type of the method. null means "don't care". */ |
| private final Class<?> returnType; |
| |
| private final String methodName; |
| |
| private final Class[] methodParams; |
| |
| /** |
| * Creates an optional method. |
| * |
| * @param returnType the return type to required, null if it does not matter |
| * @param methodName the name of the method |
| * @param methodParams the method parameter types |
| */ |
| public OptionalMethod(Class<?> returnType, String methodName, Class... methodParams) { |
| this.returnType = returnType; |
| this.methodName = methodName; |
| this.methodParams = methodParams; |
| } |
| |
| /** |
| * Returns true if the method exists on the supplied {@code target}. |
| */ |
| public boolean isSupported(T target) { |
| return getMethod(target.getClass()) != null; |
| } |
| |
| /** |
| * Invokes the method on {@code target} with {@code args}. If the method does not exist or is not |
| * public then {@code null} is returned. See also |
| * {@link #invokeOptionalWithoutCheckedException(Object, Object...)}. |
| * |
| * @throws IllegalArgumentException if the arguments are invalid |
| * @throws InvocationTargetException if the invocation throws an exception |
| */ |
| public Object invokeOptional(T target, Object... args) throws InvocationTargetException { |
| Method m = getMethod(target.getClass()); |
| if (m == null) { |
| return null; |
| } |
| try { |
| return m.invoke(target, args); |
| } catch (IllegalAccessException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Invokes the method on {@code target}. If the method does not exist or is not |
| * public then {@code null} is returned. Any RuntimeException thrown by the method is thrown, |
| * checked exceptions are wrapped in an {@link AssertionError}. |
| * |
| * @throws IllegalArgumentException if the arguments are invalid |
| */ |
| public Object invokeOptionalWithoutCheckedException(T target, Object... args) { |
| try { |
| return invokeOptional(target, args); |
| } catch (InvocationTargetException e) { |
| Throwable targetException = e.getTargetException(); |
| if (targetException instanceof RuntimeException) { |
| throw (RuntimeException) targetException; |
| } |
| AssertionError error = new AssertionError("Unexpected exception"); |
| error.initCause(targetException); |
| throw error; |
| } |
| } |
| |
| /** |
| * Invokes the method on {@code target} with {@code args}. Throws an error if the method is not |
| * supported. See also {@link #invokeWithoutCheckedException(Object, Object...)}. |
| * |
| * @throws IllegalArgumentException if the arguments are invalid |
| * @throws InvocationTargetException if the invocation throws an exception |
| */ |
| public Object invoke(T target, Object... args) throws InvocationTargetException { |
| Method m = getMethod(target.getClass()); |
| if (m == null) { |
| throw new AssertionError("Method " + methodName + " not supported for object " + target); |
| } |
| try { |
| return m.invoke(target, args); |
| } catch (IllegalAccessException e) { |
| // Method should be public: we checked. |
| AssertionError error = new AssertionError("Unexpectedly could not call: " + m); |
| error.initCause(e); |
| throw error; |
| } |
| } |
| |
| /** |
| * Invokes the method on {@code target}. Throws an error if the method is not supported. Any |
| * RuntimeException thrown by the method is thrown, checked exceptions are wrapped in |
| * an {@link AssertionError}. |
| * |
| * @throws IllegalArgumentException if the arguments are invalid |
| */ |
| public Object invokeWithoutCheckedException(T target, Object... args) { |
| try { |
| return invoke(target, args); |
| } catch (InvocationTargetException e) { |
| Throwable targetException = e.getTargetException(); |
| if (targetException instanceof RuntimeException) { |
| throw (RuntimeException) targetException; |
| } |
| AssertionError error = new AssertionError("Unexpected exception"); |
| error.initCause(targetException); |
| throw error; |
| } |
| } |
| |
| /** |
| * Perform a lookup for the method. No caching. |
| * In order to return a method the method name and arguments must match those specified when |
| * the {@link OptionalMethod} was created. If the return type is specified (i.e. non-null) it |
| * must also be compatible. The method must also be public. |
| */ |
| private Method getMethod(Class<?> clazz) { |
| Method method = null; |
| if (methodName != null) { |
| method = getPublicMethod(clazz, methodName, methodParams); |
| if (method != null |
| && returnType != null |
| && !returnType.isAssignableFrom(method.getReturnType())) { |
| |
| // If the return type is non-null it must be compatible. |
| method = null; |
| } |
| } |
| return method; |
| } |
| |
| private static Method getPublicMethod(Class<?> clazz, String methodName, Class[] parameterTypes) { |
| Method method = null; |
| try { |
| method = clazz.getMethod(methodName, parameterTypes); |
| if ((method.getModifiers() & Modifier.PUBLIC) == 0) { |
| method = null; |
| } |
| } catch (NoSuchMethodException e) { |
| // None. |
| } |
| return method; |
| } |
| } |
| |