From dc6ac48222ab96958cc6bd587df4614a2feb4c33 Mon Sep 17 00:00:00 2001 From: Adrninistrator Date: Sun, 28 Aug 2022 22:36:03 +0800 Subject: [PATCH] 0.2.0 --- README.md | 38 +++++----- build.gradle | 2 +- .../javacg/common/ClassNameConstants.java | 23 ++++++ .../javacg/common/JavaCGConstants.java | 11 ++- .../javacg/dto/ChildrenClassInfo.java | 32 --------- .../ClassInterfaceMethodInfo.java | 2 +- .../{ => classes}/ExtendsClassMethodInfo.java | 4 +- .../dto/{ => counter}/CallIdCounter.java | 2 +- .../javacg/dto/{ => jar}/JarInfo.java | 2 +- .../dto/{ => method}/MethodAttribute.java | 2 +- .../dto/{ => method}/MethodCallDto.java | 2 +- .../javacg/dto/{ => method}/MethodInfo.java | 2 +- .../{ => method}/MethodLineNumberInfo.java | 2 +- .../TmpNode4ExtendsClassMethod.java | 2 +- ...AnnotationAttributesFormatorInterface.java | 13 ++++ .../AnnotationAttributesHandler.java | 64 +++++++++++++++++ .../DefaultAnnotationAttributesFormator.java | 30 ++++++++ .../CustomCodeParserInterface.java | 8 +-- .../javacg/stat/JCallGraph.java | 68 ++++++++++++++---- .../javacg/util/HandleJarUtil.java | 10 ++- .../javacg/util/JavaCGUtil.java | 71 ++++--------------- .../{stat => visitor}/ClassVisitor.java | 48 ++++++++++--- .../{stat => visitor}/MethodVisitor.java | 64 ++++++++++++++--- .../merge_jar/TestHandleJarUtilDirFirst.java | 2 +- .../TestHandleJarUtilDirNotFirst.java | 2 +- .../merge_jar/TestHandleJarUtilDirOne.java | 2 +- .../merge_jar/TestHandleJarUtilJarMulti.java | 2 +- .../merge_jar/TestHandleJarUtilJarOne.java | 2 +- 28 files changed, 348 insertions(+), 164 deletions(-) create mode 100644 src/main/java/com/adrninistrator/javacg/common/ClassNameConstants.java delete mode 100644 src/main/java/com/adrninistrator/javacg/dto/ChildrenClassInfo.java rename src/main/java/com/adrninistrator/javacg/dto/{ => classes}/ClassInterfaceMethodInfo.java (89%) rename src/main/java/com/adrninistrator/javacg/dto/{ => classes}/ExtendsClassMethodInfo.java (85%) rename src/main/java/com/adrninistrator/javacg/dto/{ => counter}/CallIdCounter.java (89%) rename src/main/java/com/adrninistrator/javacg/dto/{ => jar}/JarInfo.java (90%) rename src/main/java/com/adrninistrator/javacg/dto/{ => method}/MethodAttribute.java (90%) rename src/main/java/com/adrninistrator/javacg/dto/{ => method}/MethodCallDto.java (90%) rename src/main/java/com/adrninistrator/javacg/dto/{ => method}/MethodInfo.java (90%) rename src/main/java/com/adrninistrator/javacg/dto/{ => method}/MethodLineNumberInfo.java (89%) rename src/main/java/com/adrninistrator/javacg/dto/{ => node}/TmpNode4ExtendsClassMethod.java (91%) create mode 100644 src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesFormatorInterface.java create mode 100644 src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesHandler.java create mode 100644 src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/DefaultAnnotationAttributesFormator.java rename src/main/java/com/adrninistrator/javacg/{stat => visitor}/ClassVisitor.java (76%) rename src/main/java/com/adrninistrator/javacg/{stat => visitor}/MethodVisitor.java (84%) diff --git a/README.md b/README.md index ae1526a..43d307f 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,12 @@ b. 对于指定目录中的后缀非.jar/.war的文件进行合并 对于某个类调用自身类的类调用关系,也会生成在输出文件中 +## 2.7. (0.2.0) + +在处理注解的属性值时,支持使用自定义类处理,自定义类需要实现`com.adrninistrator.javacg.extensions.annotation_attributes.AnnotationAttributesFormatorInterface`接口 + +可使用java-all-call-graph中的`com.adrninistrator.jacg.extensions.annotation_attributes.AllAnnotationAttributesFormator`类 + # 3. 使用说明 ## 3.1. 编译命令: @@ -233,30 +239,30 @@ type class_or_method_name annotation_name annotation_attribute_name annotation_a - annotation_attribute_value -注解属性的值,可能为空 - -注解属性值中可能会出现影响文件格式的字符,会进行以下替换处理: +注解属性值,与AnnotationAttributesFormatorInterface实现类的处理方式有关,可能为空 -|替换前的字符|替换后的字符| -|---|---| -|空格|0x01| -|\r|0x02| -|\n|0x03| +若注解没有属性值,则只有以上前三个字段,占一行 -假如属性值类型为数组,则属性值会被大括号包含,如“{test}” +若注解有属性值,则有以上五个字段,每个属性占一行 -若注解没有属性值,则只有以上前三个字段,占一行 +使用java-all-call-graph中的AllAnnotationAttributesFormator类时,注解属性值前缀的含义如下: -若注解有属性值,则有以上五个字段(若注解属性值为""则是四个字段),每个属性占一行 +|注解属性值前缀|含义|属性值的保存格式| +|---|---|---| +|s:|字符串类型,对应简单类型、类、枚举类型|属性值为字符串| +|b:|字符串类型,对应简单类型、类、枚举类型,进行BASE64编码|属性值为字符串BASE64编码后的结果| +|m:|Map类型,对应注解类型|属性值为JSON字符串| +|l:|List类型,对应数组类型|属性值为JSON字符串| 文件示例如下: ``` -C: com.test.controller.TestLoaderController org.springframework.stereotype.Controller -C: com.test.controller.TestLoaderController org.springframework.web.bind.annotation.RequestMapping value {test} -M: com.test.controller.TestRest2Controller:get(javax.servlet.http.HttpServletRequest) org.springframework.web.bind.annotation.GetMapping value {get} -M: com.test.controller.TestRest2Controller:get(javax.servlet.http.HttpServletRequest) com.test.common.annotation.TestAttributeAnnotation value abc -M: com.test.controller.TestRest2Controller:get(javax.servlet.http.HttpServletRequest) com.test.common.annotation.TestAttributeAnnotation value2 123 +C: test.call_graph.annotation.MethodWithAnnotation test.call_graph.annotation.TestAnnotation strValue b:YWFhDQo= +C: test.call_graph.annotation.MethodWithAnnotation test.call_graph.annotation.TestAnnotation intValue s:111 +C: test.call_graph.annotation.MethodWithAnnotation test.call_graph.annotation.TestAnnotation intArrayValue l:["1","2","3","4"] +C: test.call_graph.annotation.MethodWithAnnotation test.call_graph.annotation.TestAnnotation annotation1 m:{"valueB":"Cvb1","valueA":"Cva1"} +M: test.call_graph.annotation.MethodWithAnnotation:test2() test.call_graph.annotation.TestAnnotationOuter annotations l:[{"valueB":"vb1\r\n","valueA":"va1"},{"valueB":"va2","valueA":"va2"}] +M: test.call_graph.annotation.MethodWithAnnotation:test3() test.call_graph.annotation.TestAnnotationOuter2 annotations l:[{"value":"aaa","annotations":[{"valueB":"va1","valueA":"va1"},{"valueB":"va2\r\n","valueA":"va2"}]},{"value":"bbb","annotations":[{"valueB":"vb1","valueA":"vb1"},{"valueB":"vb2","valueA":"vb2"}]}] ``` ## 4.3. 方法代码行号信息文件 diff --git a/build.gradle b/build.gradle index eee8b70..9a1fc62 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'maven-publish' apply plugin: 'signing' group 'com.github.adrninistrator' -version = "0.1.9" +version = "0.2.0" def projectName = "java-callgraph2" description = "${projectName}" sourceCompatibility = 1.8 diff --git a/src/main/java/com/adrninistrator/javacg/common/ClassNameConstants.java b/src/main/java/com/adrninistrator/javacg/common/ClassNameConstants.java new file mode 100644 index 0000000..c7b1d5a --- /dev/null +++ b/src/main/java/com/adrninistrator/javacg/common/ClassNameConstants.java @@ -0,0 +1,23 @@ +package com.adrninistrator.javacg.common; + +import java.util.concurrent.Callable; + +/** + * @author adrninistrator + * @date 2022/5/14 + * @description: + */ +public class ClassNameConstants { + + public static final String CLASS_NAME_RUNNABLE = Runnable.class.getName(); + public static final String CLASS_NAME_CALLABLE = Callable.class.getName(); + public static final String CLASS_NAME_THREAD = Thread.class.getName(); + public static final String CLASS_NAME_OBJECT = Object.class.getName(); + public static final String CLASS_NAME_STRING = String.class.getName(); + public static final String CLASS_NAME_CLASS = Class.class.getName(); + public static final String CLASS_NAME_NULL_POINTER_EXCEPTION = NullPointerException.class.getName(); + + private ClassNameConstants() { + throw new IllegalStateException("illegal"); + } +} diff --git a/src/main/java/com/adrninistrator/javacg/common/JavaCGConstants.java b/src/main/java/com/adrninistrator/javacg/common/JavaCGConstants.java index 363534e..f9d89b8 100644 --- a/src/main/java/com/adrninistrator/javacg/common/JavaCGConstants.java +++ b/src/main/java/com/adrninistrator/javacg/common/JavaCGConstants.java @@ -15,6 +15,9 @@ public class JavaCGConstants { // 合并jar/war包中的class文件时,需要合并的包名 public static final String PROPERTY_MERGE_CLASS_IN_JAR_PACKAGE = "merge.class.in.jar.package"; + // 文件列的分隔符 + public static final String FILE_COLUMN_SEPARATOR = "\t"; + public static final String FILE_KEY_CLASS_PREFIX = "C:"; public static final String FILE_KEY_METHOD_PREFIX = "M:"; public static final String FILE_KEY_JAR_INFO_PREFIX = "J:"; @@ -32,8 +35,6 @@ public class JavaCGConstants { public static final String NEW_LINE = "\n"; - public static final String OBJECT_CLASS_NAME = Object.class.getName(); - public static final String MERGED_JAR_FLAG = "-javacg_merged.jar"; public static final String FILE_FLAG_ANNOTATION = "-annotation"; @@ -52,12 +53,10 @@ public class JavaCGConstants { // 输出的注解信息文件,不包含属性时的列数 public static final int ANNOTATION_COLUMN_NUM_WITHOUT_ATTRIBUTE = 3; - // 将注解属性值写入文件时,空格替换后的字符 - public static final char ANNOTATION_ATTRIBUTE_VALUE_REPLACE_BACKSPACE = 0x01; // 将注解属性值写入文件时,\r替换后的字符 - public static final char ANNOTATION_ATTRIBUTE_VALUE_REPLACE_CARRIAGE_RETURN = 0x02; + public static final char ANNOTATION_ATTRIBUTE_VALUE_REPLACE_CARRIAGE_RETURN = 0x01; // 将注解属性值写入文件时,\n替换后的字符 - public static final char ANNOTATION_ATTRIBUTE_VALUE_REPLACE_LINE_FEED = 0x03; + public static final char ANNOTATION_ATTRIBUTE_VALUE_REPLACE_LINE_FEED = 0x02; // 输出的方法行号信息文件的列数 public static final int LINE_NUMBER_COLUMN_NUM = 3; diff --git a/src/main/java/com/adrninistrator/javacg/dto/ChildrenClassInfo.java b/src/main/java/com/adrninistrator/javacg/dto/ChildrenClassInfo.java deleted file mode 100644 index d72ea76..0000000 --- a/src/main/java/com/adrninistrator/javacg/dto/ChildrenClassInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.adrninistrator.javacg.dto; - -import java.util.List; - -/** - * @author adrninistrator - * @date 2021/6/27 - * @description: - */ - -public class ChildrenClassInfo { - - private String superClassName; - - private List childrenClassNameList; - - public String getSuperClassName() { - return superClassName; - } - - public void setSuperClassName(String superClassName) { - this.superClassName = superClassName; - } - - public List getChildrenClassNameList() { - return childrenClassNameList; - } - - public void setChildrenClassNameList(List childrenClassNameList) { - this.childrenClassNameList = childrenClassNameList; - } -} diff --git a/src/main/java/com/adrninistrator/javacg/dto/ClassInterfaceMethodInfo.java b/src/main/java/com/adrninistrator/javacg/dto/classes/ClassInterfaceMethodInfo.java similarity index 89% rename from src/main/java/com/adrninistrator/javacg/dto/ClassInterfaceMethodInfo.java rename to src/main/java/com/adrninistrator/javacg/dto/classes/ClassInterfaceMethodInfo.java index dea783f..46f4c59 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/ClassInterfaceMethodInfo.java +++ b/src/main/java/com/adrninistrator/javacg/dto/classes/ClassInterfaceMethodInfo.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.classes; import java.util.List; diff --git a/src/main/java/com/adrninistrator/javacg/dto/ExtendsClassMethodInfo.java b/src/main/java/com/adrninistrator/javacg/dto/classes/ExtendsClassMethodInfo.java similarity index 85% rename from src/main/java/com/adrninistrator/javacg/dto/ExtendsClassMethodInfo.java rename to src/main/java/com/adrninistrator/javacg/dto/classes/ExtendsClassMethodInfo.java index 456895d..3e7c5b2 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/ExtendsClassMethodInfo.java +++ b/src/main/java/com/adrninistrator/javacg/dto/classes/ExtendsClassMethodInfo.java @@ -1,4 +1,6 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.classes; + +import com.adrninistrator.javacg.dto.method.MethodAttribute; import java.util.Map; diff --git a/src/main/java/com/adrninistrator/javacg/dto/CallIdCounter.java b/src/main/java/com/adrninistrator/javacg/dto/counter/CallIdCounter.java similarity index 89% rename from src/main/java/com/adrninistrator/javacg/dto/CallIdCounter.java rename to src/main/java/com/adrninistrator/javacg/dto/counter/CallIdCounter.java index a81c7df..38225cf 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/CallIdCounter.java +++ b/src/main/java/com/adrninistrator/javacg/dto/counter/CallIdCounter.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.counter; /** * @author Adrninistrator diff --git a/src/main/java/com/adrninistrator/javacg/dto/JarInfo.java b/src/main/java/com/adrninistrator/javacg/dto/jar/JarInfo.java similarity index 90% rename from src/main/java/com/adrninistrator/javacg/dto/JarInfo.java rename to src/main/java/com/adrninistrator/javacg/dto/jar/JarInfo.java index 09780c8..46bc30a 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/JarInfo.java +++ b/src/main/java/com/adrninistrator/javacg/dto/jar/JarInfo.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.jar; /** * @author adrninistrator diff --git a/src/main/java/com/adrninistrator/javacg/dto/MethodAttribute.java b/src/main/java/com/adrninistrator/javacg/dto/method/MethodAttribute.java similarity index 90% rename from src/main/java/com/adrninistrator/javacg/dto/MethodAttribute.java rename to src/main/java/com/adrninistrator/javacg/dto/method/MethodAttribute.java index e0979d0..3dfc525 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/MethodAttribute.java +++ b/src/main/java/com/adrninistrator/javacg/dto/method/MethodAttribute.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.method; /** * @author adrninistrator diff --git a/src/main/java/com/adrninistrator/javacg/dto/MethodCallDto.java b/src/main/java/com/adrninistrator/javacg/dto/method/MethodCallDto.java similarity index 90% rename from src/main/java/com/adrninistrator/javacg/dto/MethodCallDto.java rename to src/main/java/com/adrninistrator/javacg/dto/method/MethodCallDto.java index 35da118..bc89786 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/MethodCallDto.java +++ b/src/main/java/com/adrninistrator/javacg/dto/method/MethodCallDto.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.method; /** * @author adrninistrator diff --git a/src/main/java/com/adrninistrator/javacg/dto/MethodInfo.java b/src/main/java/com/adrninistrator/javacg/dto/method/MethodInfo.java similarity index 90% rename from src/main/java/com/adrninistrator/javacg/dto/MethodInfo.java rename to src/main/java/com/adrninistrator/javacg/dto/method/MethodInfo.java index dce5f66..6409790 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/MethodInfo.java +++ b/src/main/java/com/adrninistrator/javacg/dto/method/MethodInfo.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.method; import org.apache.bcel.generic.Type; diff --git a/src/main/java/com/adrninistrator/javacg/dto/MethodLineNumberInfo.java b/src/main/java/com/adrninistrator/javacg/dto/method/MethodLineNumberInfo.java similarity index 89% rename from src/main/java/com/adrninistrator/javacg/dto/MethodLineNumberInfo.java rename to src/main/java/com/adrninistrator/javacg/dto/method/MethodLineNumberInfo.java index e6a2bdd..6802192 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/MethodLineNumberInfo.java +++ b/src/main/java/com/adrninistrator/javacg/dto/method/MethodLineNumberInfo.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.method; /** * @author adrninistrator diff --git a/src/main/java/com/adrninistrator/javacg/dto/TmpNode4ExtendsClassMethod.java b/src/main/java/com/adrninistrator/javacg/dto/node/TmpNode4ExtendsClassMethod.java similarity index 91% rename from src/main/java/com/adrninistrator/javacg/dto/TmpNode4ExtendsClassMethod.java rename to src/main/java/com/adrninistrator/javacg/dto/node/TmpNode4ExtendsClassMethod.java index 1a5e229..5091549 100644 --- a/src/main/java/com/adrninistrator/javacg/dto/TmpNode4ExtendsClassMethod.java +++ b/src/main/java/com/adrninistrator/javacg/dto/node/TmpNode4ExtendsClassMethod.java @@ -1,4 +1,4 @@ -package com.adrninistrator.javacg.dto; +package com.adrninistrator.javacg.dto.node; /** * @author adrninistrator diff --git a/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesFormatorInterface.java b/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesFormatorInterface.java new file mode 100644 index 0000000..33a44cb --- /dev/null +++ b/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesFormatorInterface.java @@ -0,0 +1,13 @@ +package com.adrninistrator.javacg.extensions.annotation_attributes; + +import org.apache.bcel.classfile.ElementValuePair; + +/** + * @author adrninistrator + * @date 2022/8/28 + * @description: 对注解属性的元素值进行格式化的接口 + */ +public interface AnnotationAttributesFormatorInterface { + + String format(ElementValuePair elementValuePair); +} diff --git a/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesHandler.java b/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesHandler.java new file mode 100644 index 0000000..dbf7988 --- /dev/null +++ b/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/AnnotationAttributesHandler.java @@ -0,0 +1,64 @@ +package com.adrninistrator.javacg.extensions.annotation_attributes; + +import com.adrninistrator.javacg.common.JavaCGConstants; +import org.apache.bcel.classfile.AnnotationEntry; +import org.apache.bcel.classfile.ElementValuePair; +import org.apache.bcel.classfile.Utility; + +import java.io.Writer; + +/** + * @author adrninistrator + * @date 2022/8/28 + * @description: 对注解属性值进行处理的类 + */ +public class AnnotationAttributesHandler { + + /** + * 将注解信息写入文件 + * + * @param type 当前注解对应的元素类型,类还是方法 + * @param classOrMethod 类名或方法 + * @param annotationEntries + * @param writer + */ + public static void writeAnnotationInfo(String type, + String classOrMethod, + AnnotationEntry[] annotationEntries, + AnnotationAttributesFormatorInterface annotationAttributesFormator, + Writer writer) { + if (annotationEntries == null || annotationEntries.length == 0) { + return; + } + + try { + StringBuilder stringBuilder = new StringBuilder(); + for (AnnotationEntry annotationEntry : annotationEntries) { + String annotationClassName = Utility.typeSignatureToString(annotationEntry.getAnnotationType(), false); + // TODO 后面把空格改成\t + String data = type + " " + classOrMethod + " " + annotationClassName; + + if (annotationEntry.getElementValuePairs() == null || annotationEntry.getElementValuePairs().length == 0) { + // 注解属性为空 + stringBuilder.append(data).append(JavaCGConstants.NEW_LINE); + continue; + } + + // 注解属性非空 + for (ElementValuePair elementValuePair : annotationEntry.getElementValuePairs()) { + String formattedValue = annotationAttributesFormator.format(elementValuePair); + + stringBuilder.append(data).append(" ").append(formattedValue).append(JavaCGConstants.NEW_LINE); + } + } + + writer.write(stringBuilder.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private AnnotationAttributesHandler() { + throw new IllegalStateException("illegal"); + } +} diff --git a/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/DefaultAnnotationAttributesFormator.java b/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/DefaultAnnotationAttributesFormator.java new file mode 100644 index 0000000..f129a30 --- /dev/null +++ b/src/main/java/com/adrninistrator/javacg/extensions/annotation_attributes/DefaultAnnotationAttributesFormator.java @@ -0,0 +1,30 @@ +package com.adrninistrator.javacg.extensions.annotation_attributes; + +import com.adrninistrator.javacg.common.JavaCGConstants; +import org.apache.bcel.classfile.ElementValuePair; + +/** + * @author adrninistrator + * @date 2022/8/28 + * @description: + */ +public class DefaultAnnotationAttributesFormator implements AnnotationAttributesFormatorInterface { + + @Override + public String format(ElementValuePair elementValuePair) { + String key = elementValuePair.getNameString(); + String value = elementValuePair.getValue().toString(); + + return encodeAnnotationValue(key + JavaCGConstants.FILE_COLUMN_SEPARATOR + value); + } + + public static String encodeAnnotationValue(String value) { + return value.replace('\r', JavaCGConstants.ANNOTATION_ATTRIBUTE_VALUE_REPLACE_CARRIAGE_RETURN) + .replace('\n', JavaCGConstants.ANNOTATION_ATTRIBUTE_VALUE_REPLACE_LINE_FEED); + } + + public static String decodeAnnotationValue(String value) { + return value.replace(JavaCGConstants.ANNOTATION_ATTRIBUTE_VALUE_REPLACE_CARRIAGE_RETURN, '\r') + .replace(JavaCGConstants.ANNOTATION_ATTRIBUTE_VALUE_REPLACE_LINE_FEED, '\n'); + } +} diff --git a/src/main/java/com/adrninistrator/javacg/extensions/code_parser/CustomCodeParserInterface.java b/src/main/java/com/adrninistrator/javacg/extensions/code_parser/CustomCodeParserInterface.java index 92d9be3..28b6f59 100644 --- a/src/main/java/com/adrninistrator/javacg/extensions/code_parser/CustomCodeParserInterface.java +++ b/src/main/java/com/adrninistrator/javacg/extensions/code_parser/CustomCodeParserInterface.java @@ -1,9 +1,9 @@ package com.adrninistrator.javacg.extensions.code_parser; -import com.adrninistrator.javacg.dto.CallIdCounter; -import com.adrninistrator.javacg.dto.ClassInterfaceMethodInfo; -import com.adrninistrator.javacg.dto.ExtendsClassMethodInfo; -import com.adrninistrator.javacg.dto.MethodCallDto; +import com.adrninistrator.javacg.dto.counter.CallIdCounter; +import com.adrninistrator.javacg.dto.classes.ClassInterfaceMethodInfo; +import com.adrninistrator.javacg.dto.classes.ExtendsClassMethodInfo; +import com.adrninistrator.javacg.dto.method.MethodCallDto; import com.adrninistrator.javacg.extensions.dto.ExtendedData; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.generic.InstructionHandle; diff --git a/src/main/java/com/adrninistrator/javacg/stat/JCallGraph.java b/src/main/java/com/adrninistrator/javacg/stat/JCallGraph.java index 66b60a1..8ccdffb 100644 --- a/src/main/java/com/adrninistrator/javacg/stat/JCallGraph.java +++ b/src/main/java/com/adrninistrator/javacg/stat/JCallGraph.java @@ -1,20 +1,42 @@ package com.adrninistrator.javacg.stat; +import com.adrninistrator.javacg.common.ClassNameConstants; import com.adrninistrator.javacg.common.JavaCGConstants; -import com.adrninistrator.javacg.dto.*; +import com.adrninistrator.javacg.dto.classes.ClassInterfaceMethodInfo; +import com.adrninistrator.javacg.dto.classes.ExtendsClassMethodInfo; +import com.adrninistrator.javacg.dto.counter.CallIdCounter; +import com.adrninistrator.javacg.dto.jar.JarInfo; +import com.adrninistrator.javacg.dto.method.MethodAttribute; +import com.adrninistrator.javacg.dto.method.MethodCallDto; +import com.adrninistrator.javacg.dto.method.MethodLineNumberInfo; +import com.adrninistrator.javacg.dto.node.TmpNode4ExtendsClassMethod; import com.adrninistrator.javacg.enums.CallTypeEnum; import com.adrninistrator.javacg.enums.HandleJarResultEnum; +import com.adrninistrator.javacg.extensions.annotation_attributes.AnnotationAttributesFormatorInterface; +import com.adrninistrator.javacg.extensions.annotation_attributes.DefaultAnnotationAttributesFormator; import com.adrninistrator.javacg.extensions.code_parser.CustomCodeParserInterface; import com.adrninistrator.javacg.util.HandleJarUtil; import com.adrninistrator.javacg.util.JavaCGUtil; +import com.adrninistrator.javacg.visitor.ClassVisitor; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; -import java.io.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.Callable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -25,10 +47,6 @@ public class JCallGraph { public static final int INIT_SIZE_500 = 500; public static final int INIT_SIZE_1000 = 1000; - private static final String RUNNABLE_CLASS_NAME = Runnable.class.getName(); - private static final String CALLABLE_CLASS_NAME = Callable.class.getName(); - private static final String THREAD_CLASS_NAME = Thread.class.getName(); - private static final String METHOD_CALL_FORMAT = JavaCGConstants.FILE_KEY_METHOD_PREFIX + "%d %s:%s (%s)%s:%s %d"; private Map> calleeMethodMapGlobal; @@ -63,8 +81,11 @@ public class JCallGraph { // 处理class文件时,缓存当前处理的文件的第一层目录名及对应jar包信息 private String lastFirstDirName; + private JarInfo lastJarInfo; + private AnnotationAttributesFormatorInterface annotationAttributesFormator; + public static void main(String[] args) { JCallGraph jCallGraph = new JCallGraph(); jCallGraph.run(args); @@ -100,6 +121,18 @@ public String getMethodLineNumberOutputFilePath() { return methodLineNumberOutputFilePath; } + public void setAnnotationAttributesFormator(AnnotationAttributesFormatorInterface annotationAttributesFormator) { + this.annotationAttributesFormator = annotationAttributesFormator; + } + + private AnnotationAttributesFormatorInterface chooseAnnotationAttributesFormator() { + if (annotationAttributesFormator == null) { + annotationAttributesFormator = new DefaultAnnotationAttributesFormator(); + } + + return annotationAttributesFormator; + } + public boolean run(String[] args) { if (args == null || args.length == 0) { System.err.println("请在执行参数中指定需要处理的jar包或目录列表,使用空格分隔"); @@ -245,12 +278,16 @@ private void handleOneClass(String jarFilePath, JarEntry jarEntry, Writer result JavaClass javaClass = cp.parse(); if (handledClassNameSet.contains(javaClass.getClassName())) { - JavaCGUtil.debugPrint("跳过处理重复同名Class: " + javaClass.getClassName()); + if (JavaCGUtil.enableDebugPrint()) { + JavaCGUtil.debugPrint("跳过处理重复同名Class: " + javaClass.getClassName()); + } return; } handledClassNameSet.add(javaClass.getClassName()); - JavaCGUtil.debugPrint("处理Class: " + javaClass.getClassName()); + if (JavaCGUtil.enableDebugPrint()) { + JavaCGUtil.debugPrint("处理Class: " + javaClass.getClassName()); + } ClassVisitor classVisitor = new ClassVisitor(javaClass); classVisitor.setCalleeMethodMapGlobal(calleeMethodMapGlobal); @@ -261,6 +298,7 @@ private void handleOneClass(String jarFilePath, JarEntry jarEntry, Writer result classVisitor.setCustomCodeParserList(customCodeParserList); classVisitor.setRecordAll(recordAll); classVisitor.setAnnotationWriter(annotationWriter); + classVisitor.setAnnotationAttributesFormator(chooseAnnotationAttributesFormator()); classVisitor.start(); @@ -406,7 +444,9 @@ private void recordExtendsClassMethod(Writer resultWriter) throws IOException { // 处理一个顶层父类 private void handleOneTopSuperClass(String topSuperClassName, Writer resultWriter) throws IOException { - JavaCGUtil.debugPrint("处理一个顶层父类: " + topSuperClassName); + if (JavaCGUtil.enableDebugPrint()) { + JavaCGUtil.debugPrint("处理一个顶层父类: " + topSuperClassName); + } List tmpNodeList = new ArrayList<>(); int currentLevel = 0; @@ -638,7 +678,7 @@ private void preHandleOneFile(String jarFilePath, JarEntry jarEntry) throws IOEx // 获得父类和子类信息 String superClassName = javaClass.getSuperclassName(); - if (THREAD_CLASS_NAME.equals(superClassName)) { + if (ClassNameConstants.CLASS_NAME_THREAD.equals(superClassName)) { // 找到Thread的子类 threadChildClassMap.put(javaClass.getClassName(), Boolean.FALSE); } @@ -675,11 +715,11 @@ private void preHandleClass(JavaClass javaClass) { classInterfaceMethodInfoMap.put(className, classInterfaceMethodInfo); if (!javaClass.isAbstract()) { - if (interfaceNameList.contains(RUNNABLE_CLASS_NAME)) { + if (interfaceNameList.contains(ClassNameConstants.CLASS_NAME_RUNNABLE)) { // 找到Runnable实现类 runnableImplClassMap.put(className, Boolean.FALSE); } - if (interfaceNameList.contains(CALLABLE_CLASS_NAME)) { + if (interfaceNameList.contains(ClassNameConstants.CLASS_NAME_CALLABLE)) { // 找到Callable实现类 callableImplClassMap.put(className, Boolean.FALSE); } diff --git a/src/main/java/com/adrninistrator/javacg/util/HandleJarUtil.java b/src/main/java/com/adrninistrator/javacg/util/HandleJarUtil.java index 3a419da..ca766c2 100644 --- a/src/main/java/com/adrninistrator/javacg/util/HandleJarUtil.java +++ b/src/main/java/com/adrninistrator/javacg/util/HandleJarUtil.java @@ -1,7 +1,7 @@ package com.adrninistrator.javacg.util; import com.adrninistrator.javacg.common.JavaCGConstants; -import com.adrninistrator.javacg.dto.JarInfo; +import com.adrninistrator.javacg.dto.jar.JarInfo; import java.io.*; import java.util.*; @@ -241,14 +241,18 @@ private static void addJar2Jar(File sourceJarFile, ZipOutputStream targetZos, Li for (String mergeClassInJarPackage : mergeClassInJarPackageList) { if (jarEntryName.startsWith(mergeClassInJarPackage) || jarEntryName.startsWith("WEB-INF/classes/" + mergeClassInJarPackage)) { classPackageMatches = true; - JavaCGUtil.debugPrint("当前class文件包名匹配,需要合并 " + jarEntryName + " " + mergeClassInJarPackage); + if (JavaCGUtil.enableDebugPrint()) { + JavaCGUtil.debugPrint("当前class文件包名匹配,需要合并 " + jarEntryName + " " + mergeClassInJarPackage); + } break; } } if (!classPackageMatches) { // 跳过包名不满足要求的class文件 - JavaCGUtil.debugPrint("当前class文件包名不匹配,不合并 " + jarEntryName); + if (JavaCGUtil.enableDebugPrint()) { + JavaCGUtil.debugPrint("当前class文件包名不匹配,不合并 " + jarEntryName); + } continue; } } diff --git a/src/main/java/com/adrninistrator/javacg/util/JavaCGUtil.java b/src/main/java/com/adrninistrator/javacg/util/JavaCGUtil.java index 1b072b3..974429d 100644 --- a/src/main/java/com/adrninistrator/javacg/util/JavaCGUtil.java +++ b/src/main/java/com/adrninistrator/javacg/util/JavaCGUtil.java @@ -1,9 +1,10 @@ package com.adrninistrator.javacg.util; +import com.adrninistrator.javacg.common.ClassNameConstants; import com.adrninistrator.javacg.common.JavaCGConstants; -import com.adrninistrator.javacg.dto.ClassInterfaceMethodInfo; -import com.adrninistrator.javacg.dto.ExtendsClassMethodInfo; -import com.adrninistrator.javacg.dto.MethodInfo; +import com.adrninistrator.javacg.dto.classes.ClassInterfaceMethodInfo; +import com.adrninistrator.javacg.dto.classes.ExtendsClassMethodInfo; +import com.adrninistrator.javacg.dto.method.MethodInfo; import org.apache.bcel.Const; import org.apache.bcel.classfile.*; import org.apache.bcel.generic.Type; @@ -279,7 +280,7 @@ public static List getAllClassNameList(String className, Map getAllClassNameList(String className, Map methodCallList = new ArrayList<>(200); + private List methodLineNumberList = new ArrayList<>(100); private Map> calleeMethodMapGlobal; + private Map runnableImplClassMap; + private Map callableImplClassMap; + private Map threadChildClassMap; + private CallIdCounter callIdCounter; + private List customCodeParserList; + private boolean recordAll = false; + private Writer annotationWriter; + private AnnotationAttributesFormatorInterface annotationAttributesFormator; + public ClassVisitor(JavaClass javaClass) { this.javaClass = javaClass; cpg = new ConstantPoolGen(javaClass.getConstantPool()); @@ -54,7 +75,7 @@ public void visitConstantPool() { String referencedClass = constantPool.constantToString(constant); // 对Object类的引用不处理 - if (!JavaCGConstants.OBJECT_CLASS_NAME.equals(referencedClass)) { + if (!ClassNameConstants.CLASS_NAME_OBJECT.equals(referencedClass)) { referencedClass = JavaCGUtil.handleClassNameWithArray(referencedClass); referencedClassSet.add(referencedClass); @@ -88,6 +109,7 @@ public void visitMethod(Method method) { visitor.setCustomCodeParserList(customCodeParserList); visitor.setRecordAll(recordAll); visitor.setAnnotationWriter(annotationWriter); + visitor.setAnnotationAttributesFormator(annotationAttributesFormator); visitor.beforeStart(); visitor.start(); @@ -100,8 +122,14 @@ public void visitMethod(Method method) { public void start() { visitConstantPool(); - // 记录类上的注解信息 - JavaCGUtil.writeAnnotationInfo(JavaCGConstants.FILE_KEY_CLASS_PREFIX, javaClass.getClassName(), javaClass.getAnnotationEntries(), annotationWriter); + if (!javaClass.isAnnotation()) { + // 记录类上的注解信息,不处理注解类型的类 + AnnotationAttributesHandler.writeAnnotationInfo(JavaCGConstants.FILE_KEY_CLASS_PREFIX, + javaClass.getClassName(), + javaClass.getAnnotationEntries(), + annotationAttributesFormator, + annotationWriter); + } for (Method method : javaClass.getMethods()) { visitMethod(method); @@ -147,4 +175,8 @@ public void setRecordAll(boolean recordAll) { public void setAnnotationWriter(Writer annotationWriter) { this.annotationWriter = annotationWriter; } + + public void setAnnotationAttributesFormator(AnnotationAttributesFormatorInterface annotationAttributesFormator) { + this.annotationAttributesFormator = annotationAttributesFormator; + } } diff --git a/src/main/java/com/adrninistrator/javacg/stat/MethodVisitor.java b/src/main/java/com/adrninistrator/javacg/visitor/MethodVisitor.java similarity index 84% rename from src/main/java/com/adrninistrator/javacg/stat/MethodVisitor.java rename to src/main/java/com/adrninistrator/javacg/visitor/MethodVisitor.java index 9c167dc..ce58ad0 100644 --- a/src/main/java/com/adrninistrator/javacg/stat/MethodVisitor.java +++ b/src/main/java/com/adrninistrator/javacg/visitor/MethodVisitor.java @@ -1,16 +1,34 @@ -package com.adrninistrator.javacg.stat; +package com.adrninistrator.javacg.visitor; import com.adrninistrator.javacg.common.JavaCGConstants; -import com.adrninistrator.javacg.dto.CallIdCounter; -import com.adrninistrator.javacg.dto.MethodCallDto; -import com.adrninistrator.javacg.dto.MethodInfo; -import com.adrninistrator.javacg.dto.MethodLineNumberInfo; +import com.adrninistrator.javacg.dto.counter.CallIdCounter; +import com.adrninistrator.javacg.dto.method.MethodCallDto; +import com.adrninistrator.javacg.dto.method.MethodInfo; +import com.adrninistrator.javacg.dto.method.MethodLineNumberInfo; import com.adrninistrator.javacg.enums.CallTypeEnum; +import com.adrninistrator.javacg.extensions.annotation_attributes.AnnotationAttributesFormatorInterface; +import com.adrninistrator.javacg.extensions.annotation_attributes.AnnotationAttributesHandler; import com.adrninistrator.javacg.extensions.code_parser.CustomCodeParserInterface; import com.adrninistrator.javacg.util.JavaCGUtil; -import org.apache.bcel.classfile.*; +import org.apache.bcel.classfile.BootstrapMethod; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantInvokeDynamic; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.LineNumber; +import org.apache.bcel.classfile.LineNumberTable; +import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.EmptyVisitor; -import org.apache.bcel.generic.*; +import org.apache.bcel.generic.INVOKEDYNAMIC; +import org.apache.bcel.generic.INVOKEINTERFACE; +import org.apache.bcel.generic.INVOKESPECIAL; +import org.apache.bcel.generic.INVOKESTATIC; +import org.apache.bcel.generic.INVOKEVIRTUAL; +import org.apache.bcel.generic.Instruction; +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.InstructionList; +import org.apache.bcel.generic.InvokeInstruction; +import org.apache.bcel.generic.MethodGen; +import org.apache.bcel.generic.Type; import java.io.Writer; import java.util.HashSet; @@ -22,27 +40,43 @@ public class MethodVisitor extends EmptyVisitor { private JavaClass javaClass; + private MethodGen mg; + private ConstantPoolGen cpg; + private List methodCallList; + private List methodLineNumberList; + private LineNumberTable lineNumberTable; + private InstructionHandle ih; + private String callerFullMethod; + private Map> calleeMethodMapGlobal; + private Map runnableImplClassMap; + private Map callableImplClassMap; + private Map threadChildClassMap; + private CallIdCounter callIdCounter; + private List customCodeParserList; + private boolean recordAll = false; + private Writer annotationWriter; + private AnnotationAttributesFormatorInterface annotationAttributesFormator; + public MethodVisitor(MethodGen mg, JavaClass javaClass) { this.javaClass = javaClass; this.mg = mg; cpg = mg.getConstantPool(); - lineNumberTable = mg.getLineNumberTable(cpg); } @@ -58,7 +92,8 @@ public void beforeStart() { */ // 记录方法上的注解信息 - JavaCGUtil.writeAnnotationInfo(JavaCGConstants.FILE_KEY_METHOD_PREFIX, callerFullMethod, mg.getMethod().getAnnotationEntries(), annotationWriter); + AnnotationAttributesHandler.writeAnnotationInfo(JavaCGConstants.FILE_KEY_METHOD_PREFIX, callerFullMethod, mg.getMethod().getAnnotationEntries(), annotationAttributesFormator, + annotationWriter); // 记录当前方法对应的起止行号 if (lineNumberTable != null) { @@ -87,7 +122,12 @@ public void start() { return; } - for (ih = mg.getInstructionList().getStart(); ih != null; ih = ih.getNext()) { + InstructionList instructionList = mg.getInstructionList(); + if (instructionList == null) { + return; + } + + for (ih = instructionList.getStart(); ih != null; ih = ih.getNext()) { Instruction i = ih.getInstruction(); if (i instanceof InvokeInstruction) { @@ -293,4 +333,8 @@ public void setRecordAll(boolean recordAll) { public void setAnnotationWriter(Writer annotationWriter) { this.annotationWriter = annotationWriter; } + + public void setAnnotationAttributesFormator(AnnotationAttributesFormatorInterface annotationAttributesFormator) { + this.annotationAttributesFormator = annotationAttributesFormator; + } } diff --git a/src/test/java/merge_jar/TestHandleJarUtilDirFirst.java b/src/test/java/merge_jar/TestHandleJarUtilDirFirst.java index 70548bc..e3f238b 100644 --- a/src/test/java/merge_jar/TestHandleJarUtilDirFirst.java +++ b/src/test/java/merge_jar/TestHandleJarUtilDirFirst.java @@ -1,6 +1,6 @@ package merge_jar; -import com.adrninistrator.javacg.dto.JarInfo; +import com.adrninistrator.javacg.dto.jar.JarInfo; import com.adrninistrator.javacg.util.HandleJarUtil; import java.util.HashMap; diff --git a/src/test/java/merge_jar/TestHandleJarUtilDirNotFirst.java b/src/test/java/merge_jar/TestHandleJarUtilDirNotFirst.java index 5f07338..418c460 100644 --- a/src/test/java/merge_jar/TestHandleJarUtilDirNotFirst.java +++ b/src/test/java/merge_jar/TestHandleJarUtilDirNotFirst.java @@ -1,6 +1,6 @@ package merge_jar; -import com.adrninistrator.javacg.dto.JarInfo; +import com.adrninistrator.javacg.dto.jar.JarInfo; import com.adrninistrator.javacg.util.HandleJarUtil; import java.util.HashMap; diff --git a/src/test/java/merge_jar/TestHandleJarUtilDirOne.java b/src/test/java/merge_jar/TestHandleJarUtilDirOne.java index adcf412..565257e 100644 --- a/src/test/java/merge_jar/TestHandleJarUtilDirOne.java +++ b/src/test/java/merge_jar/TestHandleJarUtilDirOne.java @@ -1,6 +1,6 @@ package merge_jar; -import com.adrninistrator.javacg.dto.JarInfo; +import com.adrninistrator.javacg.dto.jar.JarInfo; import com.adrninistrator.javacg.util.HandleJarUtil; import java.util.HashMap; diff --git a/src/test/java/merge_jar/TestHandleJarUtilJarMulti.java b/src/test/java/merge_jar/TestHandleJarUtilJarMulti.java index 80dcb90..399f9ee 100644 --- a/src/test/java/merge_jar/TestHandleJarUtilJarMulti.java +++ b/src/test/java/merge_jar/TestHandleJarUtilJarMulti.java @@ -1,6 +1,6 @@ package merge_jar; -import com.adrninistrator.javacg.dto.JarInfo; +import com.adrninistrator.javacg.dto.jar.JarInfo; import com.adrninistrator.javacg.util.HandleJarUtil; import java.util.HashMap; diff --git a/src/test/java/merge_jar/TestHandleJarUtilJarOne.java b/src/test/java/merge_jar/TestHandleJarUtilJarOne.java index 30ede92..84a17ba 100644 --- a/src/test/java/merge_jar/TestHandleJarUtilJarOne.java +++ b/src/test/java/merge_jar/TestHandleJarUtilJarOne.java @@ -1,6 +1,6 @@ package merge_jar; -import com.adrninistrator.javacg.dto.JarInfo; +import com.adrninistrator.javacg.dto.jar.JarInfo; import com.adrninistrator.javacg.util.HandleJarUtil; import java.util.HashMap;