Browse Source

新增caPrefix支持清除指定注解

wang 2 years ago
parent
commit
23ef8fb685

+ 2 - 1
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/executor/EncryptExecutor.java

@@ -967,7 +967,8 @@ public class EncryptExecutor {
                                 return EncryptClassArgs.create(file,
                                         StrUtil.isTrueDefault(params.get(Constant.CLEAN_CLASS_ANNOTATION_PARAM_NAME), false),
                                         StrUtil.isTrueDefault(params.get(Constant.CLEAN_METHOD_ANNOTATION_PARAM_NAME), false),
-                                        StrUtil.isTrueDefault(params.get(Constant.CLEAN_FIELD_ANNOTATION_PARAM_NAME), false)
+                                        StrUtil.isTrueDefault(params.get(Constant.CLEAN_FIELD_ANNOTATION_PARAM_NAME), false),
+                                        params.get(Constant.TO_CLEAN_FIELD_ANNOTATION_PREFIX)
                                 );
                             }
                         }

+ 7 - 0
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/Constant.java

@@ -255,4 +255,11 @@ public interface Constant {
      * {@link EncryptClassArgs#isCleanAnnotationOverField()}
      */
     String CLEAN_FIELD_ANNOTATION_PARAM_NAME = "cfa";
+
+    /**
+     * 参数名:加密的类需要清除的注解全类名前缀(也可以精确匹配),不指定则为默认规则全部注解清除. 分隔符为|符号,例如:com.kk.verify|com.xx.sun
+     * <p>
+     * {@link EncryptClassArgs#getToCleanAnnotationPrefix()}
+     */
+    String TO_CLEAN_FIELD_ANNOTATION_PREFIX = "caPrefix";
 }

+ 18 - 1
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/EncryptClassArgs.java

@@ -31,6 +31,11 @@ public class EncryptClassArgs {
      * 是否清除字段的注解
      */
     private boolean cleanAnnotationOverField = false;
+
+    /**
+     * 加密的类需要清除的注解全类名前缀(也可以精确匹配),不指定则为默认规则全部注解清除. 分隔符为|符号,例如:com.xx.verify|com.xx.sun
+     */
+    private String toCleanAnnotationPrefix = "";
     
     /**
      * 是否保留原方法的参数名
@@ -41,13 +46,16 @@ public class EncryptClassArgs {
      * fast create
      */
     public static EncryptClassArgs create(File encryptClassFile, boolean cleanAnnotationOverClazz,
-                                          boolean cleanAnnotationOverMethod, boolean cleanAnnotationOverField) {
+                                          boolean cleanAnnotationOverMethod, boolean cleanAnnotationOverField,
+            String toCleanAnnotationPrefix) {
         Objects.requireNonNull(encryptClassFile, "encryptClassFile cannot be null.");
         EncryptClassArgs encryptClassArgs = new EncryptClassArgs();
         encryptClassArgs.setEncryptClassFile(encryptClassFile);
         encryptClassArgs.setCleanAnnotationOverClazz(cleanAnnotationOverClazz);
         encryptClassArgs.setCleanAnnotationOverMethod(cleanAnnotationOverMethod);
         encryptClassArgs.setCleanAnnotationOverField(cleanAnnotationOverField);
+        encryptClassArgs.setToCleanAnnotationPrefix(toCleanAnnotationPrefix);
+
         return encryptClassArgs;
     }
     
@@ -82,6 +90,14 @@ public class EncryptClassArgs {
     public void setCleanAnnotationOverField(boolean cleanAnnotationOverField) {
         this.cleanAnnotationOverField = cleanAnnotationOverField;
     }
+
+    public String getToCleanAnnotationPrefix() {
+        return toCleanAnnotationPrefix;
+    }
+
+    public void setToCleanAnnotationPrefix(String toCleanAnnotationPrefix) {
+        this.toCleanAnnotationPrefix = toCleanAnnotationPrefix;
+    }
     
     public boolean isKeepOriginArgsName() {
         return keepOriginArgsName;
@@ -98,6 +114,7 @@ public class EncryptClassArgs {
                 ", cleanAnnotationOverClazz=" + cleanAnnotationOverClazz +
                 ", cleanAnnotationOverMethod=" + cleanAnnotationOverMethod +
                 ", cleanAnnotationOverField=" + cleanAnnotationOverField +
+                ", toCleanAnnotationPrefix=" + toCleanAnnotationPrefix +
                 ", keepOriginArgsName=" + keepOriginArgsName +
                 '}';
     }

+ 33 - 10
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/JavassistUtil.java

@@ -13,6 +13,7 @@ import javassist.bytecode.Bytecode;
 import javassist.bytecode.CodeAttribute;
 import javassist.bytecode.CodeIterator;
 import javassist.bytecode.ExceptionTable;
+import javassist.bytecode.annotation.Annotation;
 import javassist.compiler.CompileError;
 import javassist.compiler.Javac;
 import winter.com.ideaaedi.classwinter.author.JustryDeng;
@@ -20,6 +21,7 @@ import winter.com.ideaaedi.classwinter.exception.ClassWinterException;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -59,9 +61,11 @@ public final class JavassistUtil {
             boolean cleanOverCLass = encryptClassArgs.isCleanAnnotationOverClazz();
             boolean cleanOverMethod = encryptClassArgs.isCleanAnnotationOverMethod();
             boolean cleanOverField = encryptClassArgs.isCleanAnnotationOverField();
+            String toCleanAnnotationPrefix = encryptClassArgs.getToCleanAnnotationPrefix();
+
             if (cleanOverCLass || cleanOverMethod || cleanOverField) {
                 try {
-                    clearAnnotation(ctClass, cleanOverCLass, cleanOverMethod, cleanOverField);
+                    clearAnnotation(ctClass, cleanOverCLass, cleanOverMethod, cleanOverField, toCleanAnnotationPrefix);
                 } catch (Exception ignore) {
                     Logger.warn(JavassistUtil.class, "clean className [" + className + "] annotation fail. ignore.");
                     // ignore
@@ -113,23 +117,23 @@ public final class JavassistUtil {
      * @param cleanOverMethod 是否清空方法上的注解
      * @param cleanOverField 是否清空字段上的注解
      */
-    private static void clearAnnotation(CtClass ctClass, boolean cleanOverCLass, boolean cleanOverMethod, boolean cleanOverField) {
+    private static void clearAnnotation(CtClass ctClass, boolean cleanOverCLass, boolean cleanOverMethod, boolean cleanOverField, String toCleanAnnotationPrefix) {
         // 清空类上的注解
         if (cleanOverCLass) {
-            removeAnnotationsAttribute(ctClass.getClassFile().getAttributes());
+            removeAnnotationsAttribute(ctClass.getClassFile().getAttributes(), toCleanAnnotationPrefix);
         }
         // 清空方法上的注解
         if (cleanOverMethod) {
             CtMethod[] methods = ctClass.getDeclaredMethods();
             for (CtMethod ctMethod : methods) {
-                removeAnnotationsAttribute(ctMethod.getMethodInfo().getAttributes());
+                removeAnnotationsAttribute(ctMethod.getMethodInfo().getAttributes(), toCleanAnnotationPrefix);
             }
         }
         // 清空字段上的注解
         if (cleanOverField) {
             CtField[] fields = ctClass.getDeclaredFields();
             for (CtField declaredField : fields) {
-                removeAnnotationsAttribute(declaredField.getFieldInfo().getAttributes());
+                removeAnnotationsAttribute(declaredField.getFieldInfo().getAttributes(), toCleanAnnotationPrefix);
             }
         }
     }
@@ -141,17 +145,36 @@ public final class JavassistUtil {
      * @return 操作是否成功
      */
     @SuppressWarnings("UnusedReturnValue")
-    private static boolean removeAnnotationsAttribute(List<AttributeInfo> attributeInfoList) {
+    private static boolean removeAnnotationsAttribute(List<AttributeInfo> attributeInfoList, String toCleanAnnotationPrefix) {
         if (attributeInfoList == null || attributeInfoList.size() == 0) {
             return true;
         }
-        return attributeInfoList.removeIf(x -> {
+        // 匹配注解全部删除
+        if (StrUtil.isBlank(toCleanAnnotationPrefix)) {
+            return attributeInfoList.removeIf(x -> {
+                try {
+                    return x instanceof AnnotationsAttribute;
+                } catch (Exception e) {
+                    return false;
+                }
+            });
+        }
+        // 删除指定注解
+        StrUtil.strToSet(toCleanAnnotationPrefix, "\\|").forEach(x -> attributeInfoList.forEach(y -> {
             try {
-                return x instanceof AnnotationsAttribute;
+                if (y instanceof AnnotationsAttribute) {
+                    AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) y;
+                    Annotation[] annotations = annotationsAttribute.getAnnotations();
+                    Annotation[] newAnnotations = Arrays.stream(annotations)
+                            .filter(annotation -> !annotation.getTypeName().startsWith(x))
+                            .toArray(Annotation[]::new);
+                    annotationsAttribute.setAnnotations(newAnnotations);
+                }
             } catch (Exception e) {
-                return false;
+                throw e;
             }
-        });
+        }));
+        return true;
     }
     
     /**

+ 14 - 2
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/StrUtil.java

@@ -115,19 +115,31 @@ public final class StrUtil {
         }
         return newStr.toString();
     }
+
+    /**
+     * 将由逗号分割的信息分割到set里面
+     *
+     * @param str 逗号分割的字符串
+     * @return 承载各个前缀信息的集合
+     */
+    public static Set<String> strToSet(String str) {
+        return strToSet(str, ",");
+    }
     
     /**
      * 将由逗号分割的信息分割到set里面
      *
      * @param str
      *            逗号分割的字符串
+     * @param split
+     *            分隔符
      * @return  承载各个前缀信息的集合
      */
-    public static Set<String> strToSet(String str) {
+    public static Set<String> strToSet(String str, String split) {
         Set<String> set = new HashSet<>();
         if (!StrUtil.isBlank(str)) {
             str = str.trim();
-            String[] arr = str.split(",");
+            String[] arr = str.split(split);
             for (String item : arr) {
                 if (StrUtil.isEmpty(item)) {
                     continue;