Skip to content

Commit be3cf73

Browse files
author
jzj
committed
First commit
1 parent 5b89577 commit be3cf73

File tree

223 files changed

+9751
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

223 files changed

+9751
-0
lines changed

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea
5+
.DS_Store
6+
/build
7+
/captures
8+
.externalNativeBuild

README.md

+782
Large diffs are not rendered by default.

build.gradle

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Top-level build file where you can add configuration options common to all sub-projects/modules.
2+
3+
buildscript {
4+
repositories {
5+
mavenLocal()
6+
mavenCentral()
7+
maven { url "https://dl.bintray.com/meituanwaimai-android/maven" }
8+
jcenter()
9+
maven {
10+
url 'https://maven.google.com/'
11+
name 'Google'
12+
}
13+
}
14+
dependencies {
15+
classpath 'com.android.tools.build:gradle:2.3.3'
16+
17+
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
18+
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
19+
20+
classpath "com.sankuai.waimai.router:plugin:$VERSION_NAME"
21+
}
22+
}
23+
24+
allprojects {
25+
repositories {
26+
mavenLocal()
27+
mavenCentral()
28+
maven { url "https://dl.bintray.com/meituanwaimai-android/maven" }
29+
jcenter()
30+
maven {
31+
url 'https://maven.google.com/'
32+
name 'Google'
33+
}
34+
}
35+
}
36+
37+
task clean(type: Delete) {
38+
delete rootProject.buildDir
39+
}

compiler/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

compiler/build.gradle

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import org.gradle.internal.jvm.Jvm
2+
3+
apply plugin: 'java'
4+
5+
dependencies {
6+
compile fileTree(dir: 'libs', include: ['*.jar'])
7+
compile 'com.google.auto.service:auto-service:1.0-rc2'
8+
compile 'com.squareup:javapoet:1.9.0'
9+
compileOnly files(Jvm.current().getToolsJar())
10+
compile project(':interfaces')
11+
}
12+
13+
sourceCompatibility = "1.7"
14+
targetCompatibility = "1.7"
15+
16+
apply from: '../gradle_mvn_push.gradle'

compiler/gradle.properties

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
POM_ARTIFACT_ID=compiler
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
package com.sankuai.waimai.router.compiler;
2+
3+
import static com.google.common.base.Charsets.UTF_8;
4+
5+
import com.sankuai.waimai.router.interfaces.Const;
6+
import com.sankuai.waimai.router.service.ServiceImpl;
7+
import com.squareup.javapoet.CodeBlock;
8+
import com.squareup.javapoet.JavaFile;
9+
import com.squareup.javapoet.MethodSpec;
10+
import com.squareup.javapoet.TypeName;
11+
import com.squareup.javapoet.TypeSpec;
12+
import com.sun.tools.javac.code.Symbol;
13+
import com.sun.tools.javac.code.Type;
14+
15+
import java.io.BufferedWriter;
16+
import java.io.IOException;
17+
import java.io.OutputStream;
18+
import java.io.OutputStreamWriter;
19+
import java.math.BigInteger;
20+
import java.security.MessageDigest;
21+
import java.security.NoSuchAlgorithmException;
22+
import java.util.Collection;
23+
import java.util.Collections;
24+
import java.util.List;
25+
26+
import javax.annotation.processing.AbstractProcessor;
27+
import javax.annotation.processing.Filer;
28+
import javax.annotation.processing.ProcessingEnvironment;
29+
import javax.lang.model.element.Element;
30+
import javax.lang.model.element.Modifier;
31+
import javax.lang.model.element.PackageElement;
32+
import javax.lang.model.element.TypeElement;
33+
import javax.lang.model.type.TypeMirror;
34+
import javax.lang.model.util.Elements;
35+
import javax.lang.model.util.Types;
36+
import javax.tools.FileObject;
37+
import javax.tools.StandardLocation;
38+
39+
/**
40+
* Created by jzj on 2018/3/23.
41+
*/
42+
43+
public abstract class BaseProcessor extends AbstractProcessor {
44+
45+
protected Filer filer;
46+
protected Types types;
47+
protected Elements elements;
48+
49+
@Override
50+
public synchronized void init(ProcessingEnvironment processingEnvironment) {
51+
super.init(processingEnvironment);
52+
filer = processingEnvironment.getFiler();
53+
types = processingEnvironment.getTypeUtils();
54+
elements = processingEnvironment.getElementUtils();
55+
}
56+
57+
public TypeMirror typeMirror(String className) {
58+
return elements.getTypeElement(className).asType();
59+
}
60+
61+
public boolean isSubType(TypeMirror type, String className) {
62+
return type != null && types.isSubtype(type, typeMirror(className));
63+
}
64+
65+
public boolean isSubType(Element element, String className) {
66+
return element != null && isSubType(element.asType(), className);
67+
}
68+
69+
public boolean isSubType(Element element, TypeMirror typeMirror) {
70+
return element != null && types.isSubtype(element.asType(), typeMirror);
71+
}
72+
73+
/**
74+
* 非抽象类
75+
*/
76+
public boolean isConcreteType(Element element) {
77+
return element instanceof TypeElement && !element.getModifiers().contains(
78+
Modifier.ABSTRACT);
79+
}
80+
81+
/**
82+
* 非抽象子类
83+
*/
84+
public boolean isConcreteSubType(Element element, String className) {
85+
return isConcreteType(element) && isSubType(element, className);
86+
}
87+
88+
/**
89+
* 非抽象子类
90+
*/
91+
public boolean isConcreteSubType(Element element, TypeMirror typeMirror) {
92+
return isConcreteType(element) && isSubType(element, typeMirror);
93+
}
94+
95+
public boolean isType(TypeMirror interfaces, String name) {
96+
return interfaces != null && interfaces.toString().equals(name);
97+
}
98+
99+
public boolean isActivity(Element element) {
100+
return isConcreteSubType(element, Const.ACTIVITY_CLASS);
101+
}
102+
103+
public boolean isHandler(Element element) {
104+
return isConcreteSubType(element, Const.URI_HANDLER_CLASS);
105+
}
106+
107+
public boolean isInterceptor(Element element) {
108+
return isConcreteSubType(element, Const.URI_INTERCEPTOR_CLASS);
109+
}
110+
111+
public static String getClassName(TypeMirror typeMirror) {
112+
return typeMirror == null ? "" : typeMirror.toString();
113+
}
114+
115+
public void writeHandlerInitClass(CodeBlock code, String hash,
116+
String genClassName, String handlerClassName, String interfaceName) {
117+
try {
118+
genClassName += Const.SPLITTER + hash;
119+
MethodSpec methodSpec = MethodSpec.methodBuilder(Const.INIT_METHOD)
120+
.addModifiers(Modifier.PUBLIC)
121+
.returns(TypeName.VOID)
122+
.addParameter(TypeName.get(typeMirror(handlerClassName)), "handler")
123+
.addCode(code)
124+
.build();
125+
TypeSpec typeSpec = TypeSpec.classBuilder(genClassName)
126+
.addSuperinterface(TypeName.get(typeMirror(interfaceName)))
127+
.addModifiers(Modifier.PUBLIC)
128+
.addMethod(methodSpec)
129+
.build();
130+
JavaFile.builder(Const.GEN_PKG, typeSpec)
131+
.build()
132+
.writeTo(filer);
133+
String fullImplName = Const.GEN_PKG + Const.DOT + genClassName;
134+
String config = new ServiceImpl(null, fullImplName, false).toConfig();
135+
writeInterfaceServiceFile(interfaceName, Collections.singletonList(config));
136+
} catch (IOException e) {
137+
e.printStackTrace();
138+
}
139+
}
140+
141+
public CodeBlock buildHandler(boolean isActivity, Symbol.ClassSymbol cls) {
142+
CodeBlock.Builder b = CodeBlock.builder();
143+
if (isActivity) {
144+
b.add("$S", cls.className());
145+
} else {
146+
b.add("new $T()", cls);
147+
}
148+
return b.build();
149+
}
150+
151+
public CodeBlock buildInterceptors(List<? extends TypeMirror> interceptors) {
152+
CodeBlock.Builder b = CodeBlock.builder();
153+
if (interceptors != null && interceptors.size() > 0) {
154+
for (TypeMirror type : interceptors) {
155+
if (type instanceof Type.ClassType) {
156+
Symbol.TypeSymbol e = ((Type.ClassType) type).asElement();
157+
if (e instanceof Symbol.ClassSymbol && isInterceptor(e)) {
158+
b.add(", new $T()", e);
159+
}
160+
}
161+
}
162+
}
163+
return b.build();
164+
}
165+
166+
public void writeInterfaceServiceFile(String interfaceName, Collection<String> lines) {
167+
writeServiceFile(Const.SERVICE_PATH + interfaceName, lines);
168+
}
169+
170+
public void writeServiceFile(String fileName, Collection<String> lines) {
171+
if (isEmpty(fileName) || isEmpty(lines)) {
172+
return;
173+
}
174+
try {
175+
FileObject res = filer.createResource(StandardLocation.CLASS_OUTPUT, "", fileName);
176+
OutputStream os = res.openOutputStream();
177+
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, UTF_8));
178+
for (String line : lines) {
179+
writer.write(line);
180+
writer.newLine();
181+
}
182+
writer.flush();
183+
os.close();
184+
} catch (IOException e) {
185+
e.printStackTrace();
186+
}
187+
}
188+
189+
public static String hash(String str) {
190+
try {
191+
MessageDigest md = MessageDigest.getInstance("MD5");
192+
md.update(str.getBytes());
193+
return new BigInteger(1, md.digest()).toString(16);
194+
} catch (NoSuchAlgorithmException e) {
195+
return Integer.toHexString(str.hashCode());
196+
}
197+
}
198+
199+
public static boolean notEmpty(String path) {
200+
return path != null && path.length() > 0;
201+
}
202+
203+
public static boolean isEmpty(String path) {
204+
return path == null || path.length() == 0;
205+
}
206+
207+
public static boolean isEmpty(Collection collection) {
208+
return collection == null || collection.isEmpty();
209+
}
210+
211+
/**
212+
* Returns the binary name of a reference type. For example,
213+
* {@code com.google.Foo$Bar}, instead of {@code com.google.Foo.Bar}.
214+
*/
215+
public static String getBinaryName(TypeElement element) {
216+
return getBinaryNameImpl(element, element.getSimpleName().toString());
217+
}
218+
219+
private static String getBinaryNameImpl(TypeElement element, String className) {
220+
Element enclosingElement = element.getEnclosingElement();
221+
222+
if (enclosingElement instanceof PackageElement) {
223+
PackageElement pkg = (PackageElement) enclosingElement;
224+
if (pkg.isUnnamed()) {
225+
return className;
226+
}
227+
return pkg.getQualifiedName() + "." + className;
228+
}
229+
230+
TypeElement typeElement = (TypeElement) enclosingElement;
231+
return getBinaryNameImpl(typeElement, typeElement.getSimpleName() + "$" + className);
232+
}
233+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.sankuai.waimai.router.compiler;
2+
3+
import com.google.auto.service.AutoService;
4+
import com.sankuai.waimai.router.annotation.RouterPage;
5+
import com.sankuai.waimai.router.interfaces.Const;
6+
import com.squareup.javapoet.CodeBlock;
7+
import com.sun.tools.javac.code.Symbol;
8+
9+
import java.util.Collections;
10+
import java.util.HashSet;
11+
import java.util.List;
12+
import java.util.Set;
13+
14+
import javax.annotation.processing.Processor;
15+
import javax.annotation.processing.RoundEnvironment;
16+
import javax.annotation.processing.SupportedSourceVersion;
17+
import javax.lang.model.SourceVersion;
18+
import javax.lang.model.element.Element;
19+
import javax.lang.model.element.TypeElement;
20+
import javax.lang.model.type.MirroredTypesException;
21+
import javax.lang.model.type.TypeMirror;
22+
23+
24+
@AutoService(Processor.class)
25+
@SupportedSourceVersion(SourceVersion.RELEASE_7)
26+
public class PageAnnotationProcessor extends BaseProcessor {
27+
28+
@Override
29+
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
30+
if (annotations == null || annotations.isEmpty()) {
31+
return false;
32+
}
33+
CodeBlock.Builder builder = CodeBlock.builder();
34+
String hash = null;
35+
for (Element element : env.getElementsAnnotatedWith(RouterPage.class)) {
36+
if (!(element instanceof Symbol.ClassSymbol)) {
37+
continue;
38+
}
39+
boolean isActivity = isActivity(element);
40+
boolean isHandler = isHandler(element);
41+
if (!isActivity && !isHandler) {
42+
continue;
43+
}
44+
45+
Symbol.ClassSymbol cls = (Symbol.ClassSymbol) element;
46+
RouterPage page = cls.getAnnotation(RouterPage.class);
47+
if (page == null) {
48+
continue;
49+
}
50+
51+
if (hash == null) {
52+
hash = hash(cls.className());
53+
}
54+
55+
CodeBlock handler = buildHandler(isActivity, cls);
56+
CodeBlock interceptors = buildInterceptors(getInterceptors(page));
57+
58+
// path, handler, interceptors
59+
String[] pathList = page.path();
60+
for (String path : pathList) {
61+
builder.addStatement("handler.register($S, $L$L)",
62+
path,
63+
handler,
64+
interceptors);
65+
}
66+
}
67+
writeHandlerInitClass(builder.build(), hash, Const.PAGE_CLASS,
68+
Const.PAGE_ANNOTATION_HANDLER_CLASS, Const.PAGE_ANNOTATION_INIT_CLASS);
69+
return true;
70+
}
71+
72+
private static List<? extends TypeMirror> getInterceptors(RouterPage page) {
73+
try {
74+
page.interceptors();
75+
} catch (MirroredTypesException mte) {
76+
return mte.getTypeMirrors();
77+
}
78+
return null;
79+
}
80+
81+
@Override
82+
public Set<String> getSupportedAnnotationTypes() {
83+
return new HashSet<>(Collections.singletonList(RouterPage.class.getName()));
84+
}
85+
}

0 commit comments

Comments
 (0)