
com.wangjie.plg.discardfile.DiscardInject.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of discardfile Show documentation
Show all versions of discardfile Show documentation
An android gradle plugin for discard class or method in compile time.
The newest version!
package com.wangjie.plg.discardfile
import com.android.annotations.NonNull
import com.android.annotations.Nullable
import com.wangjie.plg.discardfile.api.annotation.Discard
import com.wangjie.plg.discardfile.api.constant.DiscardConstant
import javassist.ClassPool
import javassist.CtClass
import javassist.CtMethod
import org.gradle.api.Project
public class DiscardInject {
public ClassPool pool/* = ClassPool.getDefault()*/;
DiscardInject(ClassPool pool) {
this.pool = pool
}
public void applyInject(Project project, String dirPath) {
pool.appendClassPath(dirPath)
File dir = new File(dirPath)
if (!dir.isDirectory()) {
return
}
def discardFileExtension = project[DiscardConstant.EXTENSION_NAME]
println "[DiscardFilePlugin] -> Configuration -> includePackagePath: " + discardFileExtension.includePackagePath + ", excludePackagePath: " + discardFileExtension.excludePackagePath
println "[DiscardFilePlugin] inject dirPath: " + dirPath
// System.setProperty(DiscardConstant.APPLY_PARAM_DEFAULT,
// String.valueOf(
// dirPath.endsWith("/release")
// ||
// dirPath.contains("/release/")
// )
// )
dir.eachFileRecurse { File file ->
String filePath = file.absolutePath
if (filePath.endsWith(".class")
&& !filePath.contains("R\$")
&& !filePath.contains("R.class")
&& !filePath.contains("BuildConfig.class")
) {
String classNamePath = filePath.replace(dirPath, "")
if (null != classNamePath && classNamePath.length() > 0) {
if (classNamePath.startsWith("$File.separatorChar")) {
classNamePath = classNamePath.substring(1)
}
// println "--------- classNamePath: " + classNamePath
if (isValidateFile(discardFileExtension, classNamePath)) {
String className = classNamePath.replaceAll("$File.separatorChar", ".")
if (className.endsWith(".class")) {
className = className.substring(0, className.length() - 6)
// println "------ className: $className"
}
CtClass ctClass = pool.get(className)
checkDefrost(ctClass)
/*
* If Add @Discard annotation at Class, discard all declared methods
*/
Discard classDiscard = ctClass.getAnnotation(Discard.class)
if (null != classDiscard) {
if (!isApplyDiscard(project, classDiscard, "Discard class : " + ctClass.getName())) {
println("[DiscardFilePlugin] -> [NOT APPLIED]Discard class : " + className)
} else {
discardClass(ctClass, classDiscard)
ctClass.writeFile(dirPath)
println("[DiscardFilePlugin] -> [APPLIED]Discard class : " + className)
}
} else {
/*
* Get all of methods that has @Discard annotations
*/
CtMethod[] ctMethods = ctClass.getDeclaredMethods()
int ctMethodsLength = ctMethods.length
for (int i = 0; i < ctMethodsLength; i++) {
CtMethod ctMethod = ctMethods[i]
Discard methodDiscard = ctMethod.getAnnotation(Discard.class)
if (null != methodDiscard) {
if (!isApplyDiscard(project, methodDiscard, "Discard method : " + ctMethod.getLongName())) {
println("[DiscardFilePlugin] -> [NOT APPLIED]Discard method : " + ctMethod.getLongName())
continue
}
println("[DiscardFilePlugin] -> [APPLIED]Discard method : " + ctMethod.getLongName())
discardMethod(ctMethod, methodDiscard)
ctClass.writeFile(dirPath)
}
}
}
// Cause ArrayIndexOutOfBoundException
// ctClass.writeFile(dirPath)
ctClass.detach()
}
}
}
}
}
private void checkDefrost(CtClass ctClass) {
if (ctClass.isFrozen()) {
ctClass.defrost()
}
}
private void discardClass(CtClass ctClass, @NonNull Discard discard) {
tryMakeClasses(discard)
// discard methods
CtMethod[] ctMethods = ctClass.getDeclaredMethods()
int ctMethodsLength = ctMethods.length
for (int i = 0; i < ctMethodsLength; i++) {
CtMethod ctMethod = ctMethods[i]
discardMethod(ctMethod, ctMethod.getAnnotation(Discard.class))
}
}
private void discardMethod(CtMethod ctMethod, @Nullable Discard discard) {
String srcCode = null;
if (null != discard) {
// Cancel this discard if it is disabled.
if (!discard.enable()) {
return;
}
tryMakeClasses(discard)
srcCode = discard.srcCode()
}
if (null == srcCode || srcCode.length() < 2) {
srcCode = "{ return " + getDefaultTypeValue(ctMethod.getReturnType()) + "; }"
}
checkDefrost(ctMethod.getDeclaringClass())
ctMethod.setBody(srcCode)
}
private boolean isApplyDiscard(Project project, Discard discard, String tag) {
String apply = discard.apply()
String[] applyParsed
if (!apply.contains("==") || 2 != ((applyParsed = apply.split("==")).length)) {
throw new RuntimeException("apply expression invalidate! -> 'key==exceptValue'")
}
String applyParamValue = getParameter(project, applyParsed[0].trim())
String applyParamExpectValue = applyParsed[1].trim()
if (null == applyParamValue || applyParamExpectValue != applyParamValue) {
println("[DiscardFilePlugin] -> [NOT APPLIED PARAM]" + tag + ", applyParam: " + apply + ", applyParamExpectValue: " + applyParamExpectValue + ", applyParamValue: " + applyParamValue)
return false;
}
return true;
}
private void tryMakeClasses(Discard discard) {
String[] paramMakeClassNames = discard.makeClassNames()
if (null != paramMakeClassNames) {
int paramMakeClassLen = paramMakeClassNames.length
for (int j = 0; j < paramMakeClassLen; j++) {
if (null == pool.find(paramMakeClassNames[j])) {
pool.makeClass(paramMakeClassNames[j])
}
}
}
}
private boolean isValidateFile(DiscardFileExtension discardFile, String classNamePath) {
// 优先检查exclude,如果包含在exclude中,则不通过
if (null != discardFile.excludePackagePath && discardFile.excludePackagePath.length > 0) {
int excludeLength = discardFile.excludePackagePath.length;
for (int i = 0; i < excludeLength; i++) {
if (classNamePath.contains(discardFile.excludePackagePath[i].replaceAll("\\.", "/"))) {
return false
}
}
}
// 如果没有设置include,则默认包含所有包
if (null == discardFile.includePackagePath || discardFile.includePackagePath.length <= 0) {
return true;
}
// 如果明确了include,则检查是否在include中
boolean isInclude = false;
int includeLength = discardFile.includePackagePath.length;
for (int i = 0; i < includeLength; i++) {
if (classNamePath.contains(discardFile.includePackagePath[i].replaceAll("\\.", "/"))) {
isInclude = true;
break
}
}
return isInclude;
}
private String getDefaultTypeValue(CtClass type) {
if (CtClass.booleanType == type) {
return "false"
} else if (CtClass.byteType == type) {
return "0"
} else if (CtClass.charType == type) {
return "0"
} else if (CtClass.doubleType == type) {
return "0"
} else if (CtClass.floatType == type) {
return "0F"
} else if (CtClass.intType == type) {
return "0"
} else if (CtClass.longType == type) {
return "0L"
} else if (CtClass.shortType == type) {
return "0"
} else {
return "null"
}
}
private String getParameter(Project project, String key) {
// -D
String value = System.getProperty(key)
if (null != value && value.length() > 0) {
return value
}
// -P
if (project.hasProperty(key)) {
return project.property(key)
}
return null
}
public void clear() {
pool = null
}
private boolean isEmpty(String string) {
return null == string || string.length() <= 0
}
private boolean isBlank(String string) {
return null == string || string.trim().length() <= 0
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy