Skip to content

Commit 53d5504

Browse files
javachefacebook-github-bot
authored andcommitted
Stop requiring registration of callable JS modules
Reviewed By: AaaChiuuu Differential Revision: D5229073 fbshipit-source-id: d6d1967982ae379733a7e9667515ca9f074aadd4
1 parent 1d30f83 commit 53d5504

File tree

3 files changed

+58
-124
lines changed

3 files changed

+58
-124
lines changed

ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public PendingJSCall(
7575
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
7676
private final Object mJSCallsPendingInitLock = new Object();
7777

78-
private final NativeModuleRegistry mJavaRegistry;
78+
private final NativeModuleRegistry mNativeModuleRegistry;
7979
private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
8080
private final MessageQueueThread mNativeModulesQueueThread;
8181
private final @Nullable MessageQueueThread mUIBackgroundQueueThread;
@@ -92,8 +92,7 @@ public PendingJSCall(
9292
private CatalystInstanceImpl(
9393
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
9494
final JavaScriptExecutor jsExecutor,
95-
final NativeModuleRegistry registry,
96-
final JavaScriptModuleRegistry jsModuleRegistry,
95+
final NativeModuleRegistry nativeModuleRegistry,
9796
final JSBundleLoader jsBundleLoader,
9897
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
9998
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
@@ -103,8 +102,8 @@ private CatalystInstanceImpl(
103102
reactQueueConfigurationSpec,
104103
new NativeExceptionHandler());
105104
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
106-
mJavaRegistry = registry;
107-
mJSModuleRegistry = jsModuleRegistry;
105+
mNativeModuleRegistry = nativeModuleRegistry;
106+
mJSModuleRegistry = new JavaScriptModuleRegistry();
108107
mJSBundleLoader = jsBundleLoader;
109108
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
110109
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
@@ -118,8 +117,8 @@ private CatalystInstanceImpl(
118117
mReactQueueConfiguration.getJSQueueThread(),
119118
mNativeModulesQueueThread,
120119
mUIBackgroundQueueThread,
121-
mJavaRegistry.getJavaModules(this),
122-
mJavaRegistry.getCxxModules());
120+
mNativeModuleRegistry.getJavaModules(this),
121+
mNativeModuleRegistry.getCxxModules());
123122
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
124123
}
125124

@@ -137,7 +136,7 @@ public BridgeCallback(CatalystInstanceImpl outer) {
137136
public void onBatchComplete() {
138137
CatalystInstanceImpl impl = mOuter.get();
139138
if (impl != null) {
140-
impl.mJavaRegistry.onBatchComplete();
139+
impl.mNativeModuleRegistry.onBatchComplete();
141140
}
142141
}
143142

@@ -294,7 +293,7 @@ public void destroy() {
294293
mNativeModulesQueueThread.runOnQueue(new Runnable() {
295294
@Override
296295
public void run() {
297-
mJavaRegistry.notifyJSInstanceDestroy();
296+
mNativeModuleRegistry.notifyJSInstanceDestroy();
298297
boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
299298
if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
300299
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
@@ -342,7 +341,7 @@ public void initialize() {
342341
mNativeModulesQueueThread.runOnQueue(new Runnable() {
343342
@Override
344343
public void run() {
345-
mJavaRegistry.notifyJSInstanceInitialized();
344+
mNativeModuleRegistry.notifyJSInstanceInitialized();
346345
}
347346
});
348347
}
@@ -359,19 +358,19 @@ public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
359358

360359
@Override
361360
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
362-
return mJavaRegistry.hasModule(nativeModuleInterface);
361+
return mNativeModuleRegistry.hasModule(nativeModuleInterface);
363362
}
364363

365364
// This is only ever called with UIManagerModule or CurrentViewerModule.
366365
@Override
367366
public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
368-
return mJavaRegistry.getModule(nativeModuleInterface);
367+
return mNativeModuleRegistry.getModule(nativeModuleInterface);
369368
}
370369

371370
// This is only used by com.facebook.react.modules.common.ModuleDataCleaner
372371
@Override
373372
public Collection<NativeModule> getNativeModules() {
374-
return mJavaRegistry.getAllModules();
373+
return mNativeModuleRegistry.getAllModules();
375374
}
376375

377376
private native void handleMemoryPressureUiHidden();
@@ -528,7 +527,6 @@ public static class Builder {
528527
private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec;
529528
private @Nullable JSBundleLoader mJSBundleLoader;
530529
private @Nullable NativeModuleRegistry mRegistry;
531-
private @Nullable JavaScriptModuleRegistry mJSModuleRegistry;
532530
private @Nullable JavaScriptExecutor mJSExecutor;
533531
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
534532

@@ -544,7 +542,6 @@ public Builder setRegistry(NativeModuleRegistry registry) {
544542
}
545543

546544
public Builder setJSModuleRegistry(JavaScriptModuleRegistry jsModuleRegistry) {
547-
mJSModuleRegistry = jsModuleRegistry;
548545
return this;
549546
}
550547

@@ -569,7 +566,6 @@ public CatalystInstanceImpl build() {
569566
Assertions.assertNotNull(mReactQueueConfigurationSpec),
570567
Assertions.assertNotNull(mJSExecutor),
571568
Assertions.assertNotNull(mRegistry),
572-
Assertions.assertNotNull(mJSModuleRegistry),
573569
Assertions.assertNotNull(mJSBundleLoader),
574570
Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
575571
}

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistration.java

Lines changed: 0 additions & 71 deletions
This file was deleted.

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,25 @@
1111

1212
import javax.annotation.Nullable;
1313

14-
import java.lang.ref.WeakReference;
1514
import java.lang.reflect.InvocationHandler;
1615
import java.lang.reflect.Method;
1716
import java.lang.reflect.Proxy;
18-
import java.util.ArrayList;
1917
import java.util.HashMap;
20-
import java.util.List;
21-
import java.util.WeakHashMap;
18+
import java.util.HashSet;
19+
import java.util.Set;
2220

23-
import com.facebook.common.logging.FLog;
24-
import com.facebook.infer.annotation.Assertions;
25-
import com.facebook.react.common.ReactConstants;
21+
import com.facebook.react.common.build.ReactBuildConfig;
2622

2723
/**
28-
* Class responsible for holding all the {@link JavaScriptModule}s registered to this
29-
* {@link CatalystInstance}. Uses Java proxy objects to dispatch method calls on JavaScriptModules
30-
* to the bridge using the corresponding module and method ids so the proper function is executed in
31-
* JavaScript.
24+
* Class responsible for holding all the {@link JavaScriptModule}s. Uses Java proxy objects
25+
* to dispatch method calls on JavaScriptModules to the bridge using the corresponding
26+
* module and method ids so the proper function is executed in JavaScript.
3227
*/
33-
public class JavaScriptModuleRegistry {
28+
public final class JavaScriptModuleRegistry {
3429
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
35-
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModuleRegistration> mModuleRegistrations;
3630

37-
public JavaScriptModuleRegistry(List<JavaScriptModuleRegistration> config) {
31+
public JavaScriptModuleRegistry() {
3832
mModuleInstances = new HashMap<>();
39-
mModuleRegistrations = new HashMap<>();
40-
for (JavaScriptModuleRegistration registration : config) {
41-
mModuleRegistrations.put(registration.getModuleInterface(), registration);
42-
}
4333
}
4434

4535
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
@@ -50,51 +40,70 @@ public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
5040
return (T) module;
5141
}
5242

53-
JavaScriptModuleRegistration registration =
54-
Assertions.assertNotNull(
55-
mModuleRegistrations.get(moduleInterface),
56-
"JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");
5743
JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
5844
moduleInterface.getClassLoader(),
5945
new Class[]{moduleInterface},
60-
new JavaScriptModuleInvocationHandler(instance, registration));
46+
new JavaScriptModuleInvocationHandler(instance, moduleInterface));
6147
mModuleInstances.put(moduleInterface, interfaceProxy);
6248
return (T) interfaceProxy;
6349
}
6450

6551
public static class Builder {
66-
private List<JavaScriptModuleRegistration> mModules =
67-
new ArrayList<JavaScriptModuleRegistration>();
68-
6952
public Builder add(Class<? extends JavaScriptModule> moduleInterfaceClass) {
70-
mModules.add(new JavaScriptModuleRegistration(moduleInterfaceClass));
7153
return this;
7254
}
7355

7456
public JavaScriptModuleRegistry build() {
75-
return new JavaScriptModuleRegistry(mModules);
57+
return new JavaScriptModuleRegistry();
7658
}
7759
}
7860

7961
private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
8062
private final CatalystInstance mCatalystInstance;
81-
private final JavaScriptModuleRegistration mModuleRegistration;
63+
private final Class<? extends JavaScriptModule> mModuleInterface;
64+
private @Nullable String mName;
8265

8366
public JavaScriptModuleInvocationHandler(
8467
CatalystInstance catalystInstance,
85-
JavaScriptModuleRegistration moduleRegistration) {
68+
Class<? extends JavaScriptModule> moduleInterface) {
8669
mCatalystInstance = catalystInstance;
87-
mModuleRegistration = moduleRegistration;
70+
mModuleInterface = moduleInterface;
71+
72+
if (ReactBuildConfig.DEBUG) {
73+
Set<String> methodNames = new HashSet<>();
74+
for (Method method : mModuleInterface.getDeclaredMethods()) {
75+
if (!methodNames.add(method.getName())) {
76+
throw new AssertionError(
77+
"Method overloading is unsupported: " + mModuleInterface.getName() +
78+
"#" + method.getName());
79+
}
80+
}
81+
}
82+
}
83+
84+
private String getJSModuleName() {
85+
if (mName == null) {
86+
// With proguard obfuscation turned on, proguard apparently (poorly) emulates inner
87+
// classes or something because Class#getSimpleName() no longer strips the outer
88+
// class name. We manually strip it here if necessary.
89+
String name = mModuleInterface.getSimpleName();
90+
int dollarSignIndex = name.lastIndexOf('$');
91+
if (dollarSignIndex != -1) {
92+
name = name.substring(dollarSignIndex + 1);
93+
}
94+
95+
// getting the class name every call is expensive, so cache it
96+
mName = name;
97+
}
98+
return mName;
8899
}
89100

90101
@Override
91102
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
92-
NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
93-
mCatalystInstance.callFunction(
94-
mModuleRegistration.getName(),
95-
method.getName(),
96-
jsArgs
97-
);
103+
NativeArray jsArgs = args != null
104+
? Arguments.fromJavaArgs(args)
105+
: new WritableNativeArray();
106+
mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);
98107
return null;
99108
}
100109
}

0 commit comments

Comments
 (0)