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
17package com.android.layoutlib.bridge.util;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21
22import java.lang.reflect.InvocationTargetException;
23import java.lang.reflect.Method;
24
25/**
26 * Utility to convert checked Reflection exceptions to unchecked exceptions.
27 */
28public class ReflectionUtils {
29
30    @NonNull
31    public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name,
32            @Nullable Class<?>... params) throws ReflectionException {
33        try {
34            return clazz.getMethod(name, params);
35        } catch (NoSuchMethodException e) {
36            throw new ReflectionException(e);
37        }
38    }
39
40    @NonNull
41    public static Method getAccessibleMethod(@NonNull Class<?> clazz, @NonNull String name,
42      @Nullable Class<?>... params) throws ReflectionException {
43        Method method = getMethod(clazz, name, params);
44        method.setAccessible(true);
45
46        return method;
47    }
48
49    @Nullable
50    public static Object invoke(@NonNull Method method, @Nullable Object object,
51            @Nullable Object... args) throws ReflectionException {
52        Exception ex;
53        try {
54            return method.invoke(object, args);
55        } catch (IllegalAccessException | InvocationTargetException e) {
56            ex = e;
57        }
58        throw new ReflectionException(ex);
59    }
60
61    /**
62     * Check if the object is an instance of a class named {@code className}. This doesn't work
63     * for interfaces.
64     */
65    public static boolean isInstanceOf(Object object, String className) {
66        Class superClass = object.getClass();
67        while (superClass != null) {
68            String name = superClass.getName();
69            if (name.equals(className)) {
70                return true;
71            }
72            superClass = superClass.getSuperclass();
73        }
74        return false;
75    }
76
77    @NonNull
78    public static Throwable getCause(@NonNull Throwable throwable) {
79        Throwable cause = throwable.getCause();
80        return cause == null ? throwable : cause;
81    }
82
83    /**
84     * Looks through the class hierarchy of {@code object} at runtime and returns the class matching
85     * the name {@code className}.
86     * <p>
87     * This is used when we cannot use Class.forName() since the class we want was loaded from a
88     * different ClassLoader.
89     */
90    @NonNull
91    public static Class<?> getClassInstance(@NonNull Object object, @NonNull String className) {
92        Class<?> superClass = object.getClass();
93        while (superClass != null) {
94            if (className.equals(superClass.getName())) {
95                return superClass;
96            }
97            superClass = superClass.getSuperclass();
98        }
99        throw new RuntimeException("invalid object/classname combination.");
100    }
101
102    /**
103     * Wraps all reflection related exceptions. Created since ReflectiveOperationException was
104     * introduced in 1.7 and we are still on 1.6
105     */
106    public static class ReflectionException extends Exception {
107        public ReflectionException() {
108            super();
109        }
110
111        public ReflectionException(String message) {
112            super(message);
113        }
114
115        public ReflectionException(String message, Throwable cause) {
116            super(message, cause);
117        }
118
119        public ReflectionException(Throwable cause) {
120            super(cause);
121        }
122    }
123}
124