Add annotation processor to create static ReactModule infos
Reviewed By: lexs Differential Revision: D3781016 fbshipit-source-id: 8169e8b55fc044df2230fd01e912c4e96a044f98
This commit is contained in:
parent
c06c1e1786
commit
605a0a62dc
|
@ -46,16 +46,27 @@ def android_library(
|
|||
*args,
|
||||
**kwargs):
|
||||
|
||||
common_processors = [
|
||||
'com.facebook.react.processing.ReactPropertyProcessor',
|
||||
]
|
||||
common_processor_deps = [
|
||||
react_native_target('java/com/facebook/react/processing:processing'),
|
||||
]
|
||||
|
||||
if react_native_target('java/com/facebook/react/uimanager/annotations:annotations') in deps and name != 'processing':
|
||||
annotation_processors = list(set(annotation_processors + common_processors))
|
||||
annotation_processor_deps = list(set(annotation_processor_deps + common_processor_deps))
|
||||
react_property_processors = [
|
||||
'com.facebook.react.processing.ReactPropertyProcessor',
|
||||
]
|
||||
react_property_processor_deps = [
|
||||
react_native_target('java/com/facebook/react/processing:processing'),
|
||||
]
|
||||
|
||||
annotation_processors = list(set(annotation_processors + react_property_processors))
|
||||
annotation_processor_deps = list(set(annotation_processor_deps + react_property_processor_deps))
|
||||
|
||||
if react_native_target('java/com/facebook/react/module/annotations:annotations') in deps and name != 'processing':
|
||||
react_module_processors = [
|
||||
'com.facebook.react.module.processing.ReactModuleSpecProcessor',
|
||||
]
|
||||
react_module_processor_deps = [
|
||||
react_native_target('java/com/facebook/react/module/processing:processing'),
|
||||
]
|
||||
|
||||
annotation_processors = list(set(annotation_processors + react_module_processors))
|
||||
annotation_processor_deps = list(set(annotation_processor_deps + react_module_processor_deps))
|
||||
|
||||
original_android_library(
|
||||
name=name,
|
||||
|
|
|
@ -245,6 +245,7 @@ android {
|
|||
java {
|
||||
srcDirs = ['src/main/java', 'src/main/libraries/soloader/java', 'src/main/jni/first-party/fb/jni/java']
|
||||
exclude 'com/facebook/react/processing'
|
||||
exclude 'com/facebook/react/module/processing'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
include_defs('//ReactAndroid/DEFS')
|
||||
|
||||
android_library(
|
||||
name = 'annotations',
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
],
|
||||
visibility=[
|
||||
'PUBLIC'
|
||||
]
|
||||
)
|
||||
|
||||
project_config(
|
||||
src_target = ':annotations',
|
||||
)
|
|
@ -7,7 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.annotations;
|
||||
package com.facebook.react.module.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.module.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
/**
|
||||
* Annotates a function that returns a list of ModuleSpecs from which we get a list of NativeModules
|
||||
* to create ReactModuleInfos from.
|
||||
*/
|
||||
@Retention(SOURCE)
|
||||
@Target(TYPE)
|
||||
public @interface ReactModuleList {
|
||||
|
||||
/**
|
||||
* The native modules in this list should be annotated with {@link ReactModule}.
|
||||
* @return List of native modules.
|
||||
*/
|
||||
Class<? extends NativeModule>[] value();
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
include_defs('//ReactAndroid/DEFS')
|
||||
|
||||
android_library(
|
||||
name = 'model',
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
],
|
||||
visibility=[
|
||||
'PUBLIC'
|
||||
]
|
||||
)
|
||||
|
||||
project_config(
|
||||
src_target = ':model',
|
||||
)
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.module.model;
|
||||
|
||||
/**
|
||||
* Data holder class holding native module specifications.
|
||||
*/
|
||||
public class ReactModuleInfo {
|
||||
|
||||
public final String mName;
|
||||
public final boolean mCanOverrideExistingModule;
|
||||
public final boolean mSupportsWebWorkers;
|
||||
public final boolean mNeedsEagerInit;
|
||||
|
||||
public ReactModuleInfo(
|
||||
String name,
|
||||
boolean canOverrideExistingModule,
|
||||
boolean supportsWebWorkers,
|
||||
boolean needsEagerInit) {
|
||||
mName = name;
|
||||
mCanOverrideExistingModule = canOverrideExistingModule;
|
||||
mSupportsWebWorkers = supportsWebWorkers;
|
||||
mNeedsEagerInit = needsEagerInit;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
include_defs('//ReactAndroid/DEFS')
|
||||
|
||||
java_library(
|
||||
name = 'processing',
|
||||
srcs = glob(['*.java']),
|
||||
source = '7',
|
||||
target = '7',
|
||||
deps = [
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/javapoet:javapoet'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
react_native_target('java/com/facebook/react/module/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/module/model:model'),
|
||||
],
|
||||
visibility=[
|
||||
'PUBLIC'
|
||||
]
|
||||
)
|
||||
|
||||
project_config(
|
||||
src_target = ':processing',
|
||||
)
|
|
@ -0,0 +1,143 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.module.processing;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.MirroredTypesException;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Elements;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.facebook.infer.annotation.SuppressFieldNotInitialized;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.module.annotations.ReactModuleList;
|
||||
import com.facebook.react.module.model.ReactModuleInfo;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
|
||||
import static javax.lang.model.element.Modifier.PUBLIC;
|
||||
|
||||
/**
|
||||
* Generates a list of ReactModuleInfo for modules annotated with {@link ReactModule} in
|
||||
* {@link ReactPackage}s annotated with {@link ReactModuleList}.
|
||||
*/
|
||||
@SupportedAnnotationTypes({
|
||||
"com.facebook.react.module.annotations.ReactModule",
|
||||
"com.facebook.react.module.annotations.ReactModuleList",
|
||||
})
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_7)
|
||||
public class ReactModuleSpecProcessor extends AbstractProcessor {
|
||||
|
||||
private static final TypeName MAP_TYPE = ParameterizedTypeName.get(
|
||||
Map.class,
|
||||
Class.class,
|
||||
ReactModuleInfo.class);
|
||||
private static final TypeName INSTANTIATED_MAP_TYPE = ParameterizedTypeName.get(HashMap.class);
|
||||
|
||||
@SuppressFieldNotInitialized
|
||||
private Filer mFiler;
|
||||
@SuppressFieldNotInitialized
|
||||
private Elements mElements;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
super.init(processingEnv);
|
||||
|
||||
mFiler = processingEnv.getFiler();
|
||||
mElements = processingEnv.getElementUtils();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
Set<? extends Element> reactModuleListElements = roundEnv.getElementsAnnotatedWith(
|
||||
ReactModuleList.class);
|
||||
for (Element reactModuleListElement : reactModuleListElements) {
|
||||
TypeElement typeElement = (TypeElement) reactModuleListElement;
|
||||
ClassName className = ClassName.get(typeElement);
|
||||
String packageName = ClassName.get(typeElement).packageName();
|
||||
String fileName = className.simpleName();
|
||||
|
||||
ReactModuleList reactModuleList = typeElement.getAnnotation(ReactModuleList.class);
|
||||
List<String> nativeModules = new ArrayList<>();
|
||||
try {
|
||||
reactModuleList.value(); // throws MirroredTypesException
|
||||
} catch (MirroredTypesException mirroredTypesException) {
|
||||
List<? extends TypeMirror> typeMirrors = mirroredTypesException.getTypeMirrors();
|
||||
for (TypeMirror typeMirror : typeMirrors) {
|
||||
nativeModules.add(typeMirror.toString());
|
||||
}
|
||||
}
|
||||
|
||||
MethodSpec getReactModuleInfosMethod = MethodSpec.methodBuilder("getReactModuleInfos")
|
||||
.addModifiers(PUBLIC)
|
||||
// TODO add function to native module interface
|
||||
// .addAnnotation(Override.class)
|
||||
.addCode(getCodeBlockForReactModuleInfos(nativeModules))
|
||||
.returns(MAP_TYPE)
|
||||
.build();
|
||||
|
||||
TypeSpec reactModulesInfosTypeSpec = TypeSpec.classBuilder(
|
||||
fileName + "$$ReactModuleInfoProvider")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addMethod(getReactModuleInfosMethod)
|
||||
.build();
|
||||
|
||||
JavaFile javaFile = JavaFile.builder(packageName, reactModulesInfosTypeSpec)
|
||||
.addFileComment("Generated by " + getClass().getName())
|
||||
.build();
|
||||
|
||||
try {
|
||||
javaFile.writeTo(mFiler);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private CodeBlock getCodeBlockForReactModuleInfos(List<String> nativeModules) {
|
||||
CodeBlock.Builder builder = CodeBlock.builder()
|
||||
.addStatement("$T map = new $T()", MAP_TYPE, INSTANTIATED_MAP_TYPE);
|
||||
|
||||
for (String nativeModule : nativeModules) {
|
||||
String keyString = nativeModule + ".class";
|
||||
|
||||
TypeElement typeElement = mElements.getTypeElement(nativeModule);
|
||||
ReactModule reactModule = typeElement.getAnnotation(ReactModule.class);
|
||||
String valueString = new StringBuilder()
|
||||
.append("new ReactModuleInfo(")
|
||||
.append("\"").append(reactModule.name()).append("\"").append(", ")
|
||||
.append(reactModule.canOverrideExistingModule()).append(", ")
|
||||
.append(reactModule.supportsWebWorkers()).append(", ")
|
||||
.append(reactModule.needsEagerInit())
|
||||
.append(")")
|
||||
.toString();
|
||||
|
||||
builder.addStatement("map.put(" + keyString + ", " + valueString + ")");
|
||||
}
|
||||
builder.addStatement("return map");
|
||||
return builder.build();
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ android_library(
|
|||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common/network:network'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/module/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/modules/core:core'),
|
||||
],
|
||||
visibility = [
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -21,6 +19,8 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ExecutorToken;
|
||||
import com.facebook.react.bridge.GuardedAsyncTask;
|
||||
|
@ -31,6 +31,7 @@ import com.facebook.react.bridge.ReadableArray;
|
|||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.network.OkHttpCallUtil;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
|
||||
|
||||
import okhttp3.Call;
|
||||
|
@ -49,6 +50,7 @@ import okhttp3.ResponseBody;
|
|||
/**
|
||||
* Implements the XMLHttpRequest JavaScript interface.
|
||||
*/
|
||||
@ReactModule(name = "RCTNetworking")
|
||||
public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
|
||||
private static final String CONTENT_ENCODING_HEADER_NAME = "content-encoding";
|
||||
|
|
Loading…
Reference in New Issue