mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
refactor: Rewrite JavaModuleWrapper from Java to Kotlin (#50882)
Summary: Rewrite of JavaModuleWrapper from Java to Kotlin in scope of https://github.com/facebook/react-native/issues/50513 ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [ANDROID] [CHANGED] - Migrated JavaModuleWrapper to Kotlin Pull Request resolved: https://github.com/facebook/react-native/pull/50882 Test Plan: Test RNTester using old arch. SampleLegacyModule is the one I've used, it needs to be enabled for old arch though (RNTesterApplication.kt -> getPackages & getReactModuleInfoProvider). I may enable SampleLegacyModule for old arch to make testing easier. mateoguzmana It breaks on `getDynamic` on old arch, but I could filter these from examples or add some fallback in SampleLegacyModule.kt for old arch. Reviewed By: cortinico Differential Revision: D73576099 Pulled By: javache fbshipit-source-id: c940be27133258fa589571a600435fa478e6b51e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c443bc18f5
commit
79d3eea0b7
-156
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.CONVERT_CONSTANTS_END;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.CONVERT_CONSTANTS_START;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.GET_CONSTANTS_END;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.GET_CONSTANTS_START;
|
||||
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
|
||||
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import com.facebook.systrace.SystraceMessage;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is part of the glue which wraps a java BaseJavaModule in a C++ NativeModule. This could all
|
||||
* be in C++, but it's android-specific initialization code, and writing it this way is easier to
|
||||
* read and means fewer JNI calls.
|
||||
*/
|
||||
@DoNotStrip
|
||||
@LegacyArchitecture
|
||||
class JavaModuleWrapper {
|
||||
static {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"JavaModuleWrapper", LegacyArchitectureLogLevel.WARNING);
|
||||
}
|
||||
|
||||
interface NativeMethod {
|
||||
void invoke(JSInstance jsInstance, ReadableArray parameters);
|
||||
|
||||
String getType();
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public static class MethodDescriptor {
|
||||
@DoNotStrip Method method;
|
||||
@DoNotStrip String signature;
|
||||
@DoNotStrip String name;
|
||||
@DoNotStrip String type;
|
||||
}
|
||||
|
||||
private final JSInstance mJSInstance;
|
||||
private final ModuleHolder mModuleHolder;
|
||||
private final ArrayList<NativeMethod> mMethods;
|
||||
private final ArrayList<MethodDescriptor> mDescs;
|
||||
|
||||
public JavaModuleWrapper(JSInstance jsInstance, ModuleHolder moduleHolder) {
|
||||
mJSInstance = jsInstance;
|
||||
mModuleHolder = moduleHolder;
|
||||
mMethods = new ArrayList<>();
|
||||
mDescs = new ArrayList<>();
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public BaseJavaModule getModule() {
|
||||
return (BaseJavaModule) mModuleHolder.getModule();
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public String getName() {
|
||||
return mModuleHolder.getName();
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
private void findMethods() {
|
||||
Systrace.beginSection(TRACE_TAG_REACT, "findMethods");
|
||||
|
||||
Class<? extends NativeModule> classForMethods = mModuleHolder.getModule().getClass();
|
||||
Class<? extends NativeModule> superClass =
|
||||
(Class<? extends NativeModule>) classForMethods.getSuperclass();
|
||||
if (TurboModule.class.isAssignableFrom(superClass)) {
|
||||
// For java module that is based on generated flow-type spec, inspect the
|
||||
// spec abstract class instead, which is the super class of the given java
|
||||
// module.
|
||||
classForMethods = superClass;
|
||||
}
|
||||
Method[] targetMethods = classForMethods.getDeclaredMethods();
|
||||
|
||||
for (Method targetMethod : targetMethods) {
|
||||
ReactMethod annotation = targetMethod.getAnnotation(ReactMethod.class);
|
||||
if (annotation != null) {
|
||||
String methodName = targetMethod.getName();
|
||||
MethodDescriptor md = new MethodDescriptor();
|
||||
JavaMethodWrapper method =
|
||||
new JavaMethodWrapper(this, targetMethod, annotation.isBlockingSynchronousMethod());
|
||||
md.name = methodName;
|
||||
md.type = method.getType();
|
||||
if (BaseJavaModule.METHOD_TYPE_SYNC.equals(md.type)) {
|
||||
md.signature = method.getSignature();
|
||||
md.method = targetMethod;
|
||||
}
|
||||
mMethods.add(method);
|
||||
mDescs.add(md);
|
||||
}
|
||||
}
|
||||
Systrace.endSection(TRACE_TAG_REACT);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public List<MethodDescriptor> getMethodDescriptors() {
|
||||
if (mDescs.isEmpty()) {
|
||||
findMethods();
|
||||
}
|
||||
return mDescs;
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public @Nullable NativeMap getConstants() {
|
||||
final String moduleName = getName();
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "JavaModuleWrapper.getConstants")
|
||||
.arg("moduleName", moduleName)
|
||||
.flush();
|
||||
ReactMarker.logMarker(GET_CONSTANTS_START, moduleName);
|
||||
|
||||
BaseJavaModule baseJavaModule = getModule();
|
||||
|
||||
Systrace.beginSection(TRACE_TAG_REACT, "module.getConstants");
|
||||
Map<String, Object> map = baseJavaModule.getConstants();
|
||||
Systrace.endSection(TRACE_TAG_REACT);
|
||||
|
||||
Systrace.beginSection(TRACE_TAG_REACT, "create WritableNativeMap");
|
||||
ReactMarker.logMarker(CONVERT_CONSTANTS_START, moduleName);
|
||||
try {
|
||||
return Arguments.makeNativeMap(map);
|
||||
} finally {
|
||||
ReactMarker.logMarker(CONVERT_CONSTANTS_END, moduleName);
|
||||
Systrace.endSection(TRACE_TAG_REACT);
|
||||
|
||||
ReactMarker.logMarker(GET_CONSTANTS_END, moduleName);
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush();
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public void invoke(int methodId, ReadableNativeArray parameters) {
|
||||
if (methodId >= mMethods.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMethods.get(methodId).invoke(mJSInstance, parameters);
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger.assertLegacyArchitecture
|
||||
import com.facebook.react.turbomodule.core.interfaces.TurboModule
|
||||
import com.facebook.systrace.Systrace
|
||||
import com.facebook.systrace.Systrace.TRACE_TAG_REACT
|
||||
import com.facebook.systrace.SystraceMessage
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* This is part of the glue which wraps a java BaseJavaModule in a C++ NativeModule. This could all
|
||||
* be in C++, but it's android-specific initialization code, and writing it this way is easier to
|
||||
* read and means fewer JNI calls.
|
||||
*/
|
||||
@DoNotStrip
|
||||
@LegacyArchitecture
|
||||
internal class JavaModuleWrapper(
|
||||
private val jsInstance: JSInstance,
|
||||
private val moduleHolder: ModuleHolder
|
||||
) {
|
||||
internal interface NativeMethod {
|
||||
fun invoke(jsInstance: JSInstance, parameters: ReadableArray)
|
||||
|
||||
val type: String
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
class MethodDescriptor {
|
||||
@DoNotStrip var method: Method? = null
|
||||
|
||||
@DoNotStrip var signature: String? = null
|
||||
|
||||
@DoNotStrip var name: String? = null
|
||||
|
||||
@DoNotStrip var type: String? = null
|
||||
}
|
||||
|
||||
private val methods = ArrayList<NativeMethod>()
|
||||
private val descs = ArrayList<MethodDescriptor>()
|
||||
|
||||
@get:DoNotStrip
|
||||
val module: BaseJavaModule
|
||||
get() = moduleHolder.module as BaseJavaModule
|
||||
|
||||
@get:DoNotStrip
|
||||
val name: String
|
||||
get() = moduleHolder.name
|
||||
|
||||
@DoNotStrip
|
||||
private fun findMethods() {
|
||||
Systrace.beginSection(TRACE_TAG_REACT, "findMethods")
|
||||
|
||||
var classForMethods: Class<out NativeModule> = moduleHolder.module.javaClass
|
||||
val superClass = classForMethods.superclass
|
||||
if (TurboModule::class.java.isAssignableFrom(superClass)) {
|
||||
// For java module that is based on generated flow-type spec, inspect the
|
||||
// spec abstract class instead, which is the super class of the given Java
|
||||
// module.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
classForMethods = superClass as Class<out NativeModule>
|
||||
}
|
||||
|
||||
val targetMethods = classForMethods.declaredMethods
|
||||
for (targetMethod in targetMethods) {
|
||||
targetMethod.getAnnotation(ReactMethod::class.java)?.let { annotation ->
|
||||
val methodName = targetMethod.name
|
||||
val md = MethodDescriptor()
|
||||
val method = JavaMethodWrapper(this, targetMethod, annotation.isBlockingSynchronousMethod)
|
||||
md.name = methodName
|
||||
md.type = method.type
|
||||
if (BaseJavaModule.METHOD_TYPE_SYNC == md.type) {
|
||||
md.signature = method.signature
|
||||
md.method = targetMethod
|
||||
}
|
||||
methods.add(method)
|
||||
descs.add(md)
|
||||
}
|
||||
}
|
||||
Systrace.endSection(TRACE_TAG_REACT)
|
||||
}
|
||||
|
||||
@get:DoNotStrip
|
||||
val methodDescriptors: List<MethodDescriptor>
|
||||
get() {
|
||||
if (descs.isEmpty()) {
|
||||
findMethods()
|
||||
}
|
||||
return descs
|
||||
}
|
||||
|
||||
@get:DoNotStrip
|
||||
val constants: NativeMap
|
||||
get() {
|
||||
val moduleName = name
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "JavaModuleWrapper.getConstants")
|
||||
.arg("moduleName", moduleName)
|
||||
.flush()
|
||||
ReactMarker.logMarker(ReactMarkerConstants.GET_CONSTANTS_START, moduleName)
|
||||
|
||||
val baseJavaModule = module
|
||||
|
||||
Systrace.beginSection(TRACE_TAG_REACT, "module.getConstants")
|
||||
val map = baseJavaModule.constants
|
||||
Systrace.endSection(TRACE_TAG_REACT)
|
||||
|
||||
Systrace.beginSection(TRACE_TAG_REACT, "create WritableNativeMap")
|
||||
ReactMarker.logMarker(ReactMarkerConstants.CONVERT_CONSTANTS_START, moduleName)
|
||||
try {
|
||||
return Arguments.makeNativeMap(map)
|
||||
} finally {
|
||||
ReactMarker.logMarker(ReactMarkerConstants.CONVERT_CONSTANTS_END, moduleName)
|
||||
Systrace.endSection(TRACE_TAG_REACT)
|
||||
|
||||
ReactMarker.logMarker(ReactMarkerConstants.GET_CONSTANTS_END, moduleName)
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush()
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
fun invoke(methodId: Int, parameters: ReadableNativeArray) {
|
||||
if (methodId >= methods.size) {
|
||||
return
|
||||
}
|
||||
|
||||
methods[methodId].invoke(jsInstance, parameters)
|
||||
}
|
||||
|
||||
companion object {
|
||||
init {
|
||||
assertLegacyArchitecture("JavaModuleWrapper", LegacyArchitectureLogLevel.WARNING)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ class BaseJavaModuleTest {
|
||||
moduleWrapper = JavaModuleWrapper(jsInstance, moduleHolder)
|
||||
methods = moduleWrapper.methodDescriptors
|
||||
val generatedModuleHolder = ModuleHolder(GeneratedMethodsModule())
|
||||
generatedModuleWrapper = JavaModuleWrapper(null, generatedModuleHolder)
|
||||
generatedModuleWrapper = JavaModuleWrapper(jsInstance, generatedModuleHolder)
|
||||
generatedMethods = generatedModuleWrapper.methodDescriptors
|
||||
arguments = mock(ReadableNativeArray::class.java)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user