1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.xwalk.core.internal;
7 import java.lang.reflect.Constructor;
8 import java.lang.reflect.InvocationTargetException;
9 import java.lang.reflect.Method;
11 import java.util.HashMap;
14 * This class is used to encapsulate the reflection invoking for bridge and wrapper.
16 * org.xwalk.core.internal.ReflectionHelper is for bridge to use. A copy will be
17 * made to org.xwalk.core.ReflectionHelper at build time for wrapper to use.
19 public class ReflectionHelper {
21 * This class contains the identical information of a constructor.
23 * Constructor of bridge and wrapper class will be initialized in the
25 * It might happen before the RefletionHelper itself being initialized.
26 * For those cases, record the information of the Constructor and load
27 * them after ReflectionHelper initialized.
29 static class ConstructorHelper {
30 private String fullClassName;
31 private Object[] paramTypes;
33 Constructor<?> loadConstructor() {
34 Class<?> clazz = loadClass(fullClassName);
35 Class<?>[] params = new Class<?>[paramTypes.length];
36 for (int i = 0; i < paramTypes.length; i++) {
37 Object type = paramTypes[i];
38 // paramTypes can be string or Class<?>, if it's string,
39 // it means it's not in bridge/wrapper's classLoader,
40 // we need to load it from wrapper/bridge's loader.
41 if (type instanceof Class<?>) {
42 params[i] = (Class<?>) type;
43 } else if (type instanceof String) {
44 params[i] = loadClass((String) type);
48 return clazz.getConstructor(params);
49 } catch (NoSuchMethodException e) {
50 ReflectionHelper.handleException(e);
55 ConstructorHelper(String className, Object... paramTypes) {
56 this.fullClassName = className;
57 this.paramTypes = paramTypes;
61 private static Map<Class<?>, Method> sBridgeWrapperMap = new HashMap<Class<?>, Method>();
62 private static Map<String, Constructor<?>> sConstructorMap = new HashMap<String, Constructor<?>>();
63 private static Map<String, ConstructorHelper> sConstructorHelperMap =
64 new HashMap<String, ConstructorHelper>();
65 private static ClassLoader sBridgeOrWrapperLoader = null;
66 private static boolean sIsWrapper;
67 private final static String INTERNAL_PACKAGE = "org.xwalk.core.internal";
69 public static void init(boolean crossPackage) {
72 initClassLoader(ReflectionHelper.class.getClassLoader());
74 // TODO(wang16): Support shared mode and initClassLoader cross package.
78 public static void initClassLoader(ClassLoader loader) {
79 sBridgeOrWrapperLoader = loader;
80 sBridgeWrapperMap.clear();
81 sConstructorMap.clear();
83 for (String name : sConstructorHelperMap.keySet()) {
84 ConstructorHelper helper = sConstructorHelperMap.get(name);
85 if (helper != null) sConstructorMap.put(name, helper.loadConstructor());
88 // Load the helper in bridge side and invoke the initClassLoader method of it
89 // with wrapper's classloader via reflection.
90 Class<?> helperInBridge =
91 sBridgeOrWrapperLoader.loadClass(INTERNAL_PACKAGE + "." + "ReflectionHelper");
92 Method initInBridge = helperInBridge.getMethod("initClassLoader", ClassLoader.class);
93 initInBridge.invoke(null, ReflectionHelper.class.getClassLoader());
95 // JavascriptInterface is an annotation class bridge will use but declared in
97 Class<?> javascriptInterface =
98 sBridgeOrWrapperLoader.loadClass("org.xwalk.core.JavascriptInterface");
99 Class<?> xwalkContentInInternal =
100 ReflectionHelper.class.getClassLoader().loadClass(
101 INTERNAL_PACKAGE + "." + "XWalkContent");
102 Method setJavascriptInterface = xwalkContentInInternal.getDeclaredMethod(
103 "setJavascriptInterfaceClass", javascriptInterface.getClass());
104 setJavascriptInterface.invoke(null, javascriptInterface);
106 } catch (Exception e) {
111 public static void registerConstructor(String name, String clazz, Object... params) {
112 sConstructorHelperMap.put(name, new ConstructorHelper(clazz, params));
115 public static Class<?> loadClass(String clazz) {
116 // Any embedder using Embedding API should only use the exposed APIs which are
117 // in wrapper, so the initialization process is always starting from wrapper.
118 if (sBridgeOrWrapperLoader == null) init(false);
120 return sBridgeOrWrapperLoader.loadClass(clazz);
121 } catch (ClassNotFoundException e) {
127 public static Method loadMethod(Class<?> clazz, String name, Object... paramTypes) {
128 Class<?>[] params = new Class<?>[paramTypes.length];
129 for (int i = 0; i < paramTypes.length; i++) {
130 Object type = paramTypes[i];
131 if (type instanceof Class<?>) {
132 params[i] = (Class<?>) type;
133 } else if (type instanceof String) {
134 params[i] = loadClass((String) type);
138 return clazz.getMethod(name, params);
139 } catch (NoSuchMethodException e) {
145 public static void handleException(Exception e) {
147 throw new RuntimeException(e);
150 public static void handleException(String e) {
151 handleException(new RuntimeException(e));
154 public static Object createInstance(String name, Object... parameters) {
156 Constructor<?> creator = sConstructorMap.get(name);
157 if (creator == null) {
158 ConstructorHelper helper = sConstructorHelperMap.get(name);
159 if (helper != null) {
160 creator = helper.loadConstructor();
161 sConstructorMap.put(name, creator);
164 if (creator != null) {
166 ret = creator.newInstance(parameters);
167 } catch (IllegalArgumentException e) {
169 } catch (InstantiationException e) {
171 } catch (IllegalAccessException e) {
173 } catch (InvocationTargetException e) {
180 public static Object invokeMethod(Method m, Object instance, Object... parameters) {
184 ret = m.invoke(instance, parameters);
185 } catch (IllegalArgumentException e) {
187 } catch (IllegalAccessException e) {
189 } catch (InvocationTargetException e) {
191 } catch (NullPointerException e) {
198 // Convert between wrapper and bridge instance.
199 public static Object getBridgeOrWrapper(Object instance) {
200 if (instance == null) return null;
201 Class<?> clazz = instance.getClass();
202 Method method = sBridgeWrapperMap.get(clazz);
203 if (method == null) {
204 String methodName = "getBridge";
206 methodName = "getWrapper";
209 method = clazz.getMethod(methodName);
210 } catch (NoSuchMethodException e) {
213 if (method != null) sBridgeWrapperMap.put(clazz, method);
215 return invokeMethod(method, instance);
218 private static boolean isWrapper() {
219 return !ReflectionHelper.class.getPackage().getName().equals(INTERNAL_PACKAGE);
223 sIsWrapper = isWrapper();