1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.layoutlib.bridge.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 22 import java.lang.reflect.InvocationHandler; 23 import java.lang.reflect.InvocationTargetException; 24 import java.lang.reflect.Method; 25 import java.lang.reflect.Proxy; 26 27 /** 28 * Utility to convert checked Reflection exceptions to unchecked exceptions. 29 */ 30 public class ReflectionUtils { 31 32 @NonNull getMethod(@onNull Class<?> clazz, @NonNull String name, @Nullable Class<?>... params)33 public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name, 34 @Nullable Class<?>... params) throws ReflectionException { 35 try { 36 return clazz.getMethod(name, params); 37 } catch (NoSuchMethodException e) { 38 throw new ReflectionException(e); 39 } 40 } 41 42 @NonNull getAccessibleMethod(@onNull Class<?> clazz, @NonNull String name, @Nullable Class<?>... params)43 public static Method getAccessibleMethod(@NonNull Class<?> clazz, @NonNull String name, 44 @Nullable Class<?>... params) throws ReflectionException { 45 Method method = getMethod(clazz, name, params); 46 method.setAccessible(true); 47 48 return method; 49 } 50 51 @Nullable invoke(@onNull Method method, @Nullable Object object, @Nullable Object... args)52 public static Object invoke(@NonNull Method method, @Nullable Object object, 53 @Nullable Object... args) throws ReflectionException { 54 Exception ex; 55 try { 56 return method.invoke(object, args); 57 } catch (IllegalAccessException | InvocationTargetException e) { 58 ex = e; 59 } 60 throw new ReflectionException(ex); 61 } 62 63 /** 64 * Check if the object is an instance of a class named {@code className}. This doesn't work 65 * for interfaces. 66 */ isInstanceOf(Object object, String className)67 public static boolean isInstanceOf(Object object, String className) { 68 Class superClass = object.getClass(); 69 while (superClass != null) { 70 String name = superClass.getName(); 71 if (name.equals(className)) { 72 return true; 73 } 74 superClass = superClass.getSuperclass(); 75 } 76 return false; 77 } 78 79 /** 80 * Check if the object is an instance of any of the class named in {@code className}. This 81 * doesn't work for interfaces. 82 */ isInstanceOf(Object object, String[] classNames)83 public static boolean isInstanceOf(Object object, String[] classNames) { 84 Class superClass = object.getClass(); 85 while (superClass != null) { 86 String name = superClass.getName(); 87 for (String className : classNames) { 88 if (name.equals(className)) { 89 return true; 90 } 91 } 92 superClass = superClass.getSuperclass(); 93 } 94 return false; 95 } 96 97 @NonNull getCause(@onNull Throwable throwable)98 public static Throwable getCause(@NonNull Throwable throwable) { 99 Throwable cause = throwable.getCause(); 100 return cause == null ? throwable : cause; 101 } 102 103 /** 104 * Looks through the class hierarchy of {@code object} at runtime and returns the class matching 105 * the name {@code className}. 106 * <p> 107 * This is used when we cannot use Class.forName() since the class we want was loaded from a 108 * different ClassLoader. 109 */ 110 @NonNull getClassInstance(@onNull Object object, @NonNull String className)111 public static Class<?> getClassInstance(@NonNull Object object, @NonNull String className) { 112 Class<?> superClass = object.getClass(); 113 while (superClass != null) { 114 if (className.equals(superClass.getName())) { 115 return superClass; 116 } 117 superClass = superClass.getSuperclass(); 118 } 119 throw new RuntimeException("invalid object/classname combination."); 120 } 121 createProxy(Class<T> interfaze)122 public static <T> T createProxy(Class<T> interfaze) { 123 ClassLoader loader = interfaze.getClassLoader(); 124 return (T) Proxy.newProxyInstance(loader, new Class[]{interfaze}, new InvocationHandler() { 125 public Object invoke(Object proxy, Method m, Object[] args) { 126 final Class<?> returnType = m.getReturnType(); 127 if (returnType == boolean.class) { 128 return false; 129 } else if (returnType == int.class) { 130 return 0; 131 } else if (returnType == long.class) { 132 return 0L; 133 } else if (returnType == short.class) { 134 return 0; 135 } else if (returnType == char.class) { 136 return 0; 137 } else if (returnType == byte.class) { 138 return 0; 139 } else if (returnType == float.class) { 140 return 0f; 141 } else if (returnType == double.class) { 142 return 0.0; 143 } else { 144 return null; 145 } 146 } 147 }); 148 } 149 150 /** 151 * Wraps all reflection related exceptions. Created since ReflectiveOperationException was 152 * introduced in 1.7 and we are still on 1.6 153 */ 154 public static class ReflectionException extends Exception { 155 public ReflectionException() { 156 super(); 157 } 158 159 public ReflectionException(String message) { 160 super(message); 161 } 162 163 public ReflectionException(String message, Throwable cause) { 164 super(message, cause); 165 } 166 167 public ReflectionException(Throwable cause) { 168 super(cause); 169 } 170 } 171 } 172