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 a class named {@code className}. This doesn't work 81 * for interfaces. 82 */ isInstanceOf(Object object, String[] classNames)83 public static boolean isInstanceOf(Object object, String[] classNames) { 84 return getParentClass(object, classNames) != null; 85 } 86 87 /** 88 * Check if the object is an instance of any of the class named in {@code className} and 89 * returns the name of the parent class that matched. This doesn't work for interfaces. 90 */ 91 @Nullable getParentClass(Object object, String[] classNames)92 public static String getParentClass(Object object, String[] classNames) { 93 Class superClass = object.getClass(); 94 while (superClass != null) { 95 String name = superClass.getName(); 96 for (String className : classNames) { 97 if (name.equals(className)) { 98 return className; 99 } 100 } 101 superClass = superClass.getSuperclass(); 102 } 103 return null; 104 } 105 106 @NonNull getCause(@onNull Throwable throwable)107 public static Throwable getCause(@NonNull Throwable throwable) { 108 Throwable cause = throwable.getCause(); 109 return cause == null ? throwable : cause; 110 } 111 112 /** 113 * Looks through the class hierarchy of {@code object} at runtime and returns the class matching 114 * the name {@code className}. 115 * <p> 116 * This is used when we cannot use Class.forName() since the class we want was loaded from a 117 * different ClassLoader. 118 */ 119 @NonNull getClassInstance(@onNull Object object, @NonNull String className)120 public static Class<?> getClassInstance(@NonNull Object object, @NonNull String className) { 121 Class<?> superClass = object.getClass(); 122 while (superClass != null) { 123 if (className.equals(superClass.getName())) { 124 return superClass; 125 } 126 superClass = superClass.getSuperclass(); 127 } 128 throw new RuntimeException("invalid object/classname combination."); 129 } 130 createProxy(Class<T> interfaze)131 public static <T> T createProxy(Class<T> interfaze) { 132 ClassLoader loader = interfaze.getClassLoader(); 133 return (T) Proxy.newProxyInstance(loader, new Class[]{interfaze}, new InvocationHandler() { 134 public Object invoke(Object proxy, Method m, Object[] args) { 135 final Class<?> returnType = m.getReturnType(); 136 if (returnType == boolean.class) { 137 return false; 138 } else if (returnType == int.class) { 139 return 0; 140 } else if (returnType == long.class) { 141 return 0L; 142 } else if (returnType == short.class) { 143 return 0; 144 } else if (returnType == char.class) { 145 return 0; 146 } else if (returnType == byte.class) { 147 return 0; 148 } else if (returnType == float.class) { 149 return 0f; 150 } else if (returnType == double.class) { 151 return 0.0; 152 } else { 153 return null; 154 } 155 } 156 }); 157 } 158 159 /** 160 * Wraps all reflection related exceptions. Created since ReflectiveOperationException was 161 * introduced in 1.7 and we are still on 1.6 162 */ 163 public static class ReflectionException extends Exception { 164 public ReflectionException() { 165 super(); 166 } 167 168 public ReflectionException(String message) { 169 super(message); 170 } 171 172 public ReflectionException(String message, Throwable cause) { 173 super(message, cause); 174 } 175 176 public ReflectionException(Throwable cause) { 177 super(cause); 178 } 179 } 180 } 181