use of com.didi.drouter.annotation.Service in project DRouter by didi.
the class ServiceCollect method generate.
@Override
public void generate(File routerDir) throws Exception {
CtClass ctClass = pool.makeClass(getPackageName() + ".ServiceLoader");
CtClass superClass = pool.get("com.didi.drouter.store.MetaLoader");
ctClass.setSuperclass(superClass);
StringBuilder builder = new StringBuilder();
builder.append("public void load(java.util.Map data) {\n");
CtClass featureInterface = pool.get("com.didi.drouter.service.IFeatureMatcher");
for (CtClass serviceCc : serviceClass.values()) {
try {
if (isNonStaticInnerClass(serviceCc)) {
throw new Exception("Annotation can not use non static inner class");
}
Annotation annotation = getAnnotation(serviceCc, Service.class);
ArrayMemberValue functionValue = (ArrayMemberValue) annotation.getMemberValue("function");
String[] aliasValue = ((Service) serviceCc.getAnnotation(Service.class)).alias();
ArrayMemberValue featureValue = (ArrayMemberValue) annotation.getMemberValue("feature");
int priority = ((Service) serviceCc.getAnnotation(Service.class)).priority();
int cacheValue = ((Service) serviceCc.getAnnotation(Service.class)).cache();
boolean anyAbility = false;
List<CtClass> functionCcList = new ArrayList<>();
for (int i = 0; i < functionValue.getValue().length; i++) {
ClassMemberValue functionCmv = (ClassMemberValue) functionValue.getValue()[i];
if ("com.didi.drouter.service.AnyAbility".equals(functionCmv.getValue())) {
anyAbility = true;
} else {
CtClass functionCc = getCtClass(functionCmv.getValue());
functionCcList.add(functionCc);
String[] superClassNames;
if ("com.didi.drouter.service.ICallService".equals(functionCmv.getValue())) {
superClassNames = new String[11];
for (int j = 0; j < 10; j++) {
superClassNames[j] = "com.didi.drouter.service.ICallService" + j;
}
superClassNames[10] = "com.didi.drouter.service.ICallServiceN";
} else {
superClassNames = new String[] { functionCc.getName() };
}
// ICallService should use unique alias, for using alias to determine which service
if (functionCmv.getValue().startsWith("com.didi.drouter.service.ICallService")) {
if (i <= aliasValue.length - 1) {
String duplicate = StoreUtil.insertCallAlias(aliasValue[i], serviceCc);
if (duplicate != null) {
throw new Exception("ICallService can't use the same alias with" + duplicate);
}
}
}
if (!checkSuper(serviceCc, superClassNames)) {
throw new Exception("@Service with function does not match interface");
}
}
}
if (anyAbility) {
functionCcList.clear();
functionCcList.addAll(collectSuper(serviceCc));
if (aliasValue.length > 1) {
throw new Exception("only use one alias at most to match AnyAbility");
}
if (featureValue != null && featureValue.getValue().length > 1) {
throw new Exception("only use one feature at most to match AnyAbility");
}
}
// traverse all the function argument, one function corresponding one function->(impl,feature) data
for (int i = 0; i < functionCcList.size(); i++) {
CtClass functionCc = functionCcList.get(i);
String alias = "";
if (aliasValue.length == 1) {
alias = aliasValue[0];
} else if (i < aliasValue.length) {
// affirm no AnyAbility
alias = aliasValue[i];
}
// one feature generator one feature matcher class
CtClass featureCc = null;
CtClass featureMatchCc = null;
if (featureValue != null) {
if (featureValue.getValue().length == 1) {
ClassMemberValue featureCmv = (ClassMemberValue) featureValue.getValue()[0];
featureCc = pool.get(featureCmv.getValue());
} else if (i < featureValue.getValue().length) {
// affirm no AnyAbility
ClassMemberValue featureCmv = (ClassMemberValue) featureValue.getValue()[i];
featureCc = pool.get(featureCmv.getValue());
}
}
if (featureCc != null) {
// avoid class duplication
String featureMatcher = MATCH + serviceCc.getName().replace(".", "_") + "__" + featureCc.getSimpleName();
featureMatchCc = pool.getOrNull(featureMatcher);
if (featureMatchCc == null) {
featureMatchCc = pool.makeClass(featureMatcher);
featureMatchCc.addInterface(featureInterface);
StringBuilder featureBuilder = new StringBuilder();
featureBuilder.append("\npublic boolean match(Object obj) {");
featureBuilder.append("\n return obj instanceof ");
featureBuilder.append(featureCc.getName());
completeMatchMethod(serviceCc, featureCc, featureBuilder);
featureBuilder.append(";\n}");
// Logger.d(featureBuilder.toString());
generatorClass(routerDir, featureMatchCc, featureBuilder.toString());
}
}
CtClass methodProxyCc = null;
String constructorMethod = null;
String executeMethod = null;
try {
CtConstructor constructor = serviceCc.getDeclaredConstructor(null);
if (constructor != null) {
constructorMethod = String.format("public java.lang.Object newInstance(android.content.Context context) {" + "{ return new %s();} }", serviceCc.getName());
}
} catch (NotFoundException ignore) {
}
CtMethod[] ctMethods = serviceCc.getMethods();
if (ctMethods != null) {
StringBuilder allIfStr = new StringBuilder();
Set<String> methodNames = new HashSet<>();
for (CtMethod method : ctMethods) {
boolean add = methodNames.add(method.getName() + "_$$_" + method.getParameterTypes().length);
Remote remote = (Remote) method.getAnnotation(Remote.class);
if (remote != null) {
if (!add) {
throw new Exception(String.format("The method \"%s\" with @Remote " + "can't be same name and same parameter count", method.getName()));
}
CtClass returnCc = method.getReturnType();
checkPrimitiveType(method.getName(), returnCc);
CtClass[] paraTypeCts = method.getParameterTypes();
StringBuilder para = new StringBuilder();
if (paraTypeCts != null) {
// argument type
for (int j = 0; j < paraTypeCts.length; j++) {
checkPrimitiveType(method.getName(), paraTypeCts[j]);
para.append(String.format("(%s) (args[%s])", paraTypeCts[j].getName(), j));
if (j != paraTypeCts.length - 1) {
para.append(",");
}
}
}
// return type
if (!"void".equals(returnCc.getName())) {
allIfStr.append(String.format("if (\"%s\".equals(methodName)) { return ((%s)instance).%s(%s); }", method.getName() + "_$$_" + method.getParameterTypes().length, serviceCc.getName(), method.getName(), para));
} else {
allIfStr.append(String.format("if (\"%s\".equals(methodName)) { ((%s)instance).%s(%s); return null; }", method.getName() + "_$$_" + method.getParameterTypes().length, serviceCc.getName(), method.getName(), para));
}
}
}
executeMethod = String.format("public java.lang.Object execute(Object instance, String methodName, Object[] " + "args) {" + "%s" + "throw " + "new com.didi.drouter.store.IRouterProxy.RemoteMethodMatchException();" + "}", allIfStr);
}
if (constructorMethod != null || executeMethod != null) {
CtClass proxyInterface = pool.get("com.didi.drouter.store.IRouterProxy");
String path = PROXY + serviceCc.getName().replace(".", "_");
methodProxyCc = pool.getOrNull(path);
if (methodProxyCc == null) {
methodProxyCc = pool.makeClass(path);
methodProxyCc.addInterface(proxyInterface);
generatorClass(routerDir, methodProxyCc, constructorMethod == null ? METHOD1 : constructorMethod, executeMethod == null ? METHOD2 : executeMethod);
}
}
StringBuilder itemBuilder = new StringBuilder();
itemBuilder.append(" put(");
itemBuilder.append(functionCc.getName());
itemBuilder.append(".class, com.didi.drouter.store.RouterMeta.build(");
itemBuilder.append("com.didi.drouter.store.RouterMeta.SERVICE)");
itemBuilder.append(".assembleService(");
itemBuilder.append(serviceCc.getName());
itemBuilder.append(".class, ");
itemBuilder.append(methodProxyCc != null ? "new " + methodProxyCc.getName() + "()" : "null");
itemBuilder.append(", \"");
itemBuilder.append(alias);
itemBuilder.append("\",");
itemBuilder.append(featureMatchCc != null ? "new " + featureMatchCc.getName() + "()" : "null");
itemBuilder.append(",");
itemBuilder.append(priority);
itemBuilder.append(",");
itemBuilder.append(cacheValue);
itemBuilder.append(")");
itemBuilder.append(", data);\n");
items.add(itemBuilder.toString());
}
} catch (Exception e) {
e.printStackTrace();
throw new Exception("Class: === " + serviceCc.getName() + " ===\nCause: " + e.getMessage());
}
}
Collections.sort(items);
for (String item : items) {
builder.append(item);
}
builder.append("}");
Logger.d("\nclass ServiceLoader" + "\n" + builder.toString());
generatorClass(routerDir, ctClass, builder.toString());
}
Aggregations