Merge ReactMethod and ReactSyncHook

Reviewed By: astreet

Differential Revision: D4409726

fbshipit-source-id: 7a0091da754b114680772aa9c0a898b1aa721ba5
This commit is contained in:
Pieter De Baets
2017-01-30 06:39:45 -08:00
committed by Facebook Github Bot
parent 412acd237a
commit 59226f022c
7 changed files with 85 additions and 133 deletions

View File

@@ -176,12 +176,18 @@ public abstract class BaseJavaModule implements NativeModule {
private final int mJSArgumentsNeeded;
private final String mTraceName;
public JavaMethod(Method method) {
public JavaMethod(Method method, boolean isSync) {
mMethod = method;
mMethod.setAccessible(true);
if (isSync) {
mType = METHOD_TYPE_SYNC;
}
// TODO: create these lazily
Class[] parameterTypes = method.getParameterTypes();
mArgumentExtractors = buildArgumentExtractors(parameterTypes);
mSignature = buildSignature(parameterTypes);
mSignature = buildSignature(mMethod, parameterTypes, isSync);
// Since native methods are invoked from a message queue executed on a single thread, it is
// save to allocate only one arguments object per method that can be reused across calls
mArguments = new Object[parameterTypes.length];
@@ -197,9 +203,16 @@ public abstract class BaseJavaModule implements NativeModule {
return mSignature;
}
private String buildSignature(Class[] paramTypes) {
StringBuilder builder = new StringBuilder(paramTypes.length);
builder.append("v.");
private String buildSignature(Method method, Class[] paramTypes, boolean isSync) {
StringBuilder builder = new StringBuilder(paramTypes.length + 2);
if (isSync) {
builder.append(returnTypeToChar(method.getReturnType()));
builder.append('.');
} else {
builder.append("v.");
}
for (int i = 0; i < paramTypes.length; i++) {
Class paramClass = paramTypes[i];
if (paramClass == ExecutorToken.class) {
@@ -212,7 +225,9 @@ public abstract class BaseJavaModule implements NativeModule {
} else if (paramClass == Promise.class) {
Assertions.assertCondition(
i == paramTypes.length - 1, "Promise must be used as last parameter only");
mType = METHOD_TYPE_PROMISE;
if (!isSync) {
mType = METHOD_TYPE_PROMISE;
}
}
builder.append(paramTypeToChar(paramClass));
}
@@ -352,6 +367,7 @@ public abstract class BaseJavaModule implements NativeModule {
* Determines how the method is exported in JavaScript:
* METHOD_TYPE_ASYNC for regular methods
* METHOD_TYPE_PROMISE for methods that return a promise object to the caller.
* METHOD_TYPE_SYNC for sync methods
*/
@Override
public String getType() {
@@ -359,82 +375,28 @@ public abstract class BaseJavaModule implements NativeModule {
}
}
public class SyncJavaHook implements SyncNativeHook {
private Method mMethod;
private final String mSignature;
public SyncJavaHook(Method method) {
mMethod = method;
mMethod.setAccessible(true);
mSignature = buildSignature(method);
}
public Method getMethod() {
return mMethod;
}
public String getSignature() {
return mSignature;
}
private String buildSignature(Method method) {
Class[] paramTypes = method.getParameterTypes();
StringBuilder builder = new StringBuilder(paramTypes.length + 2);
builder.append(returnTypeToChar(method.getReturnType()));
builder.append('.');
for (int i = 0; i < paramTypes.length; i++) {
Class paramClass = paramTypes[i];
if (paramClass == ExecutorToken.class) {
if (!BaseJavaModule.this.supportsWebWorkers()) {
throw new RuntimeException(
"Module " + BaseJavaModule.this + " doesn't support web workers, but " +
mMethod.getName() +
" takes an ExecutorToken.");
}
} else if (paramClass == Promise.class) {
Assertions.assertCondition(
i == paramTypes.length - 1, "Promise must be used as last parameter only");
}
builder.append(paramTypeToChar(paramClass));
}
return builder.toString();
}
}
private @Nullable Map<String, NativeMethod> mMethods;
private @Nullable Map<String, SyncNativeHook> mHooks;
private void findMethods() {
if (mMethods == null) {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "findMethods");
mMethods = new HashMap<>();
mHooks = new HashMap<>();
Method[] targetMethods = getClass().getDeclaredMethods();
for (Method targetMethod : targetMethods) {
if (targetMethod.getAnnotation(ReactMethod.class) != null) {
ReactMethod annotation = targetMethod.getAnnotation(ReactMethod.class);
if (annotation != null) {
String methodName = targetMethod.getName();
if (mHooks.containsKey(methodName) || mMethods.containsKey(methodName)) {
if (mMethods.containsKey(methodName)) {
// We do not support method overloading since js sees a function as an object regardless
// of number of params.
throw new IllegalArgumentException(
"Java Module " + getName() + " sync method name already registered: " + methodName);
"Java Module " + getName() + " method name already registered: " + methodName);
}
mMethods.put(methodName, new JavaMethod(targetMethod));
}
if (targetMethod.getAnnotation(ReactSyncHook.class) != null) {
String methodName = targetMethod.getName();
if (mHooks.containsKey(methodName) || mMethods.containsKey(methodName)) {
// We do not support method overloading since js sees a function as an object regardless
// of number of params.
throw new IllegalArgumentException(
"Java Module " + getName() + " sync method name already registered: " + methodName);
}
mHooks.put(methodName, new SyncJavaHook(targetMethod));
mMethods.put(
methodName,
new JavaMethod(targetMethod,
annotation.isBlockingSynchronousMethod()));
}
}
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
@@ -454,11 +416,6 @@ public abstract class BaseJavaModule implements NativeModule {
return null;
}
public final Map<String, SyncNativeHook> getSyncHooks() {
findMethods();
return assertNotNull(mHooks);
}
@Override
public void initialize() {
// do nothing