From 830f8b5c60a21613033ee2c732128754928f9285 Mon Sep 17 00:00:00 2001 From: chief Date: Tue, 25 May 2021 23:37:16 +0800 Subject: [PATCH 1/6] =?UTF-8?q?Jetty=209=E7=9A=84=E5=9B=BE=E5=92=8C?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cd/basic-architecture-patterns.png | Bin 0 -> 44966 bytes .../cdtocode/doc/basic-architecture.adoc | 178 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/main/resources/cdtocode/cd/basic-architecture-patterns.png create mode 100644 src/main/resources/cdtocode/doc/basic-architecture.adoc diff --git a/src/main/resources/cdtocode/cd/basic-architecture-patterns.png b/src/main/resources/cdtocode/cd/basic-architecture-patterns.png new file mode 100644 index 0000000000000000000000000000000000000000..777eed91c15ffbd9e3931055f27fabb1cb83aee8 GIT binary patch literal 44966 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¬PFHC?${(`dTy=(g$#j= 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 C=16_c@xy_GYS~Zze!Q| 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 Date: Wed, 26 May 2021 22:23:50 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E5=B7=B2=E8=AF=BB=E5=8F=96=E5=AE=8CUML?= =?UTF-8?q?=E5=9B=BE=E8=AF=86=E5=88=AB=E7=BB=93=E6=9E=9C=E3=80=82=E4=B8=8B?= =?UTF-8?q?=E4=B8=80=E6=AD=A5=E8=AF=BB=E5=8F=96code=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E4=B8=8B=E6=89=80=E6=9C=89java=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .classpath | 2 + .../hy/java/uct/cdtocode/CDToCodeTracer.java | 25 +++-- .../uct/cdtocode/mapper/InitialMapper.java | 9 ++ .../hy/java/uct/cdtocode/reader/CDReader.java | 93 ++++++++++++++++++ .../java/uct/cdtocode/reader/CodeReader.java | 11 +++ .../java/uct/cdtocode/reader/DocReader.java | 13 +++ .../hy/java/uct/umlrecog/util/Relation.java | 3 + src/main/resources/cd/temp result.png | Bin 4373 -> 3502 bytes ...ture-patterns.png => cd-eclipse_jetty.png} | Bin .../cdtocode/cd/cd-eclipse_jetty.txt | 60 +++++++++++ 10 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java create mode 100644 src/main/java/com/hy/java/uct/cdtocode/reader/CDReader.java create mode 100644 src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java create mode 100644 src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java rename src/main/resources/cdtocode/cd/{basic-architecture-patterns.png => cd-eclipse_jetty.png} (100%) create mode 100644 src/main/resources/cdtocode/cd/cd-eclipse_jetty.txt diff --git a/.classpath b/.classpath index d390ad0..59b8c5d 100644 --- a/.classpath +++ b/.classpath @@ -2,6 +2,8 @@ + + diff --git a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java index cbc29a9..ca4b917 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java +++ b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java @@ -1,11 +1,12 @@ package com.hy.java.uct.cdtocode; -import java.io.File; -import java.io.FileNotFoundException; +import java.util.Map; -import com.github.javaparser.StaticJavaParser; -import com.github.javaparser.ast.CompilationUnit; -import com.hy.java.utility.common.FileEditor; +import com.hy.java.uct.cdtocode.mapper.InitialMapper; +import com.hy.java.uct.cdtocode.reader.CDReader; +import com.hy.java.uct.cdtocode.reader.CodeReader; +import com.hy.java.uct.cdtocode.reader.DocReader; +import com.hy.java.uct.umlrecog.util.UMLClass; public class CDToCodeTracer { /** @@ -14,12 +15,12 @@ public class CDToCodeTracer { private static final String cd_dir = System.getProperty("user.dir") + "\\src\\main\\resources\\cdtocode\\cd\\"; /** - * 将要设计文档放在doc_dir目录下 + * 将设计文档放在doc_dir目录下 */ private static final String doc_dir = System.getProperty("user.dir") + "\\src\\main\\resources\\cdtocode\\doc\\"; /** - * 将要追踪的代码放在cd_dir目录下 + * 将要追踪的代码放在code_dir目录下 */ private static final String code_dir = System.getProperty("user.dir") + "\\src\\main\\resources\\cdtocode\\code\\"; @@ -30,15 +31,21 @@ public class CDToCodeTracer { /* * 1、读取模型信息 */ - FileEditor model_file = new FileEditor(cd_dir); + // 读取完UML图识别结果后,将实体信息保存在classes_in_CD里 + Map classes_in_CD = CDReader.read(cd_dir + "cd-eclipse_jetty.txt"); + // 检查读取结果,可注释掉 + CDReader.check(classes_in_CD); /* * 2、读取文档信息 */ + DocReader.read(doc_dir + "basic-architecture.adoc"); /* - * 3、读取code目录下所有java文件名 + * 3、读取code目录下所有java文件 */ + CodeReader.read(code_dir); /* * 4、遍历模型中的实体元素(类或对象),针对每个元素,在code中寻找能匹配的java文件 */ + InitialMapper.map(); } } diff --git a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java new file mode 100644 index 0000000..dbde150 --- /dev/null +++ b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java @@ -0,0 +1,9 @@ +package com.hy.java.uct.cdtocode.mapper; + +public class InitialMapper { + + public static void map() { + // TODO Auto-generated method stub + + } +} diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/CDReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/CDReader.java new file mode 100644 index 0000000..1b0450d --- /dev/null +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/CDReader.java @@ -0,0 +1,93 @@ +package com.hy.java.uct.cdtocode.reader; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.hy.java.uct.umlrecog.util.Relation; +import com.hy.java.uct.umlrecog.util.UMLClass; +import com.hy.java.utility.common.FileEditor; + +public class CDReader { + /** + * 读取UML图识别结果,将实体信息保存在result里并返回 + */ + public static Map read(String cd_recog_res_path) { + Map result = new HashMap<>(); + // UML图识别结果 + FileEditor model_file = new FileEditor(cd_recog_res_path); + // 保存类名、属性、方法。类之间以“#”隔开 + String[] class_strs = model_file.readFileToString().split("#"); + for (String class_str : class_strs) { + UMLClass UML_class = new UMLClass(); + // 类名、属性、方法用“@”隔开 + String[] class_info_strs = class_str.split("@"); + // 类名 + UML_class.setTitle(class_info_strs[0].substring(class_info_strs[0].lastIndexOf(")") + 1, class_info_strs[0].length() - 1)); + // 属性 + if (class_info_strs[1].length() > 0) { + UML_class.setAttrisStr(class_info_strs[1].substring(0, class_info_strs[1].length() - 1)); + } else { + UML_class.setAttrisStr(class_info_strs[1]); + } + // 方法 + if (class_info_strs[2].length() > 0) { + UML_class.setMethodsStr(class_info_strs[2].substring(0, class_info_strs[2].length() - 1)); + } else { + UML_class.setMethodsStr(class_info_strs[2]); + } + result.put(UML_class.getTitle(), UML_class); + } + // 根据类名保存关系(出、入两类) + for (String class_str : class_strs) { + String[] class_info_strs = class_str.split("@"); + UMLClass UML_class = result.get(class_info_strs[0].substring(class_info_strs[0].lastIndexOf(")") + 1, class_info_strs[0].length() - 1)); + // 出 + if (class_info_strs.length >= 4) { + if (!class_info_strs[3].isBlank()) { + // 关系用“¥”隔开 + String[] out_relas = class_info_strs[3].split("¥"); + for (String out_rela_str : out_relas) { + Relation relation = new Relation(); + String[] rela_info = out_rela_str.split("%"); + relation.source = result.get(rela_info[0].substring(0, rela_info[0].length() - 1)); + relation.target = result.get(rela_info[1].substring(0, rela_info[1].length() - 1)); + relation.type = rela_info[2]; + UML_class.out_relas.add(relation); + } + } + } + // 入 + if (class_info_strs.length == 5) { + // 关系用“¥”隔开 + String[] in_relas = class_info_strs[4].split("¥"); + for (String in_rela_str : in_relas) { + Relation relation = new Relation(); + String[] rela_info = in_rela_str.split("%"); + relation.source = result.get(rela_info[0].substring(0, rela_info[0].length() - 1)); + relation.target = result.get(rela_info[1].substring(0, rela_info[1].length() - 1)); + relation.type = rela_info[2]; + UML_class.in_relas.add(relation); + } + } + } + return result; + } + + public static void check(Map classes_in_CD) { + Set keys = classes_in_CD.keySet(); + for (String key : keys) { + UMLClass uc = classes_in_CD.get(key); + System.out.println("类名:" + uc.getTitle()); + System.out.println("属性:" + uc.getAttrisStr()); + System.out.println("方法:" + uc.getMethodsStr()); + for (Relation r : uc.out_relas) { + System.out.println("出关:" + r.source.getTitle() + "→" + r.target.getTitle() + "是" + r.type); + } + for (Relation r : uc.in_relas) { + System.out.println("入关:" + r.source.getTitle() + "→" + r.target.getTitle() + "是" + r.type); + } + System.out.println("======================="); + } + } +} diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java new file mode 100644 index 0000000..ae2dd33 --- /dev/null +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java @@ -0,0 +1,11 @@ +package com.hy.java.uct.cdtocode.reader; + +import com.hy.java.utility.common.Traverser; +import com.hy.java.utility.common.Traverser.FileNode; + +public class CodeReader { + + public static void read(String code_dir) { + FileNode code_dir_root = Traverser.traverseDir(code_dir); + } +} diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java new file mode 100644 index 0000000..8437a1b --- /dev/null +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java @@ -0,0 +1,13 @@ +package com.hy.java.uct.cdtocode.reader; + +import com.hy.java.utility.common.FileEditor; + +public class DocReader { + /** + * 读取文档信息 + */ + public static void read(String doc_file_path) { + FileEditor doc_file = new FileEditor(doc_file_path); + System.out.println(doc_file.readFileToString()); + } +} diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/Relation.java b/src/main/java/com/hy/java/uct/umlrecog/util/Relation.java index c4a983f..a0b379e 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/Relation.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/Relation.java @@ -14,4 +14,7 @@ public class Relation { public Relation(PolygonalLine poly_line) { this.poly_line = poly_line; } + + public Relation() { + } } diff --git a/src/main/resources/cd/temp result.png b/src/main/resources/cd/temp result.png index 0dc87447b2f8ca34540b52902217acfeb1732ef8..d943a61799c37b3054433cc772380bb90c3a130e 100644 GIT binary patch literal 3502 zcmeHKZ%7+w7{APbd0QoVg~m9oQ7<~sYFf3Sj!eBXdN-#%N&_CeGN_=wS~L##>2j@DXjy-la$0 zgwKIuMQxbrF<-9dY-=dn{CM}O@A`5#6&yYY(nwFbbr^IljA6b6Vuo2m!>&?~(mEUq z{XC!epk*{axLidL!AD7P66YB0|kFvO_;^*Wiz%B#m(?8L~FC%)}-KH!hAQG#zo;IWP}l#7=AGSYp9P8^BQ^Mv{jH9wp$Yg? zL&OTbrx*DIF(T54k7(zEqSd0$e_5#hiBYVed9TdrUx5Esq=VQ*$QNU~G*g2;%y}tz z5;sYD((J8r^jqaM2VJ5H9Kqfz$jx+jl;WeJ$2}{?&@EQBgz{(!{{ZH5MK|+sHmqS> z!pt|^!P{agBv+yLI2ufhR^oKz^`_bieEkx0!7g-Om4HyhbN)p)HjKeu#!e^SNmLA> zq+zCy`N+y%aBf+2<%>#7D)SAq5`<#V`Eku}aIT%Ii~8f&DIY7@d5S9}{5tA-lSdc> zLh;I~k$Ga_*kYd`kKUFphIIZi0P&t5CB~_9OMkALLNV%#Gd{?SUZK{MS=on)P+`7|Gk%sCsOC}#|I~zuOMzsvXjkfzKAhI8 zd@(ZEqCtx5x*(QDjP%6vMEFVyLI}kBgac||3B=Y#BH;c24AEmFq$k8vF(aVIzsrVP zkpmOvI|rkm+ZXisC%h{j%9`aQ%=?&Z@1rLnC8qK4VT%@e>L%v!XIUb}Wa2jIjWBNi zmY0ZqGz9tCGcr^GcbE_)^_(;D z{Qf(G<*J!gxzMKeUHpqaL88CGeEi0lBwugWa(S?W+Ypg|$3A?gRRkFx*B(0dZT{H$ o`r;5hzHD=l+^hHSu6_4}<#+yG)m1pFM)?mhN?%j{J^n%WzlMsGasU7T literal 4373 zcmeHLU2IZk7(Vn=uu^_zw{!{v)RHFqIpC(H{vf#3xQ5N{&om~-Qih9hmU>Rl{u(NU zR?Bf}-Oer!3rl;m#O%h_?P7<;{!m!!2{gSjt>X*ZrXb8j;&&Ft$SDOAX7E5$G zo*c6A0t1IJhNy8c(CM*ck85~=H)Kp;GG-)+)pD@Z8!G;S@3>OxjTTNhN0UD1XyNpv z#Beu(b=rul+@cL(2Rw|3gO@fH~6zL_Y(dBH?DslsHnN@>omkWL(F1u1UE^`A$R;~8IQD46U~^zPsk z%C8N)C_`NlkXs8K7Y)6Xws zu+RB4sKx$7-#XHgb+zzcxtS{UDEFoSuaA2Qi9RuKi*E&u)ysgFOStM=zR>?&U2+u0 z9*1yU8GS`4Uz!Y%f%JAa(|F3#R7yJcMhg;}6Q-Kvya;Vm00*PSSciuHMW2HS_81r> zTw~gc9;S+3f%OY>KLQmtbkDZ}sa*`7GypAqqyNo0)iwVCa8}#+6U^NzY9*3Kk~q!c<2Vub2@LNQGm0w z9kG^%wN@Fe13U)2kxJm422MDvy#YN&Pl;00iBT20M@?FWVSl9ZU-srwUk`}sFGQ)P zN@RyDJcOWaD$;qFN$-~DzVlfw!T7-0Kziq2O~x?xeGPv)N&RHz#3AjphpFr-0(Ipy z3i3XQ1f=01J=*pZ>9jG$RDT9Mte%hR`a&bdz5wBQou1ykMowR_BkfWRq8>-HRc3S# z=#XP>rlTBb-@N=~u_(ElpiC;#(zapc*0%;x0}USaM7%(+hZ0$v25Dc41(vVt>0AlUer7{%7oB5hTo%?&oeFf6g6J|t4Rl-G6`8o-ArB_|ryN~k z^j;lkm*;#D_1ds@M1*u| Date: Wed, 26 May 2021 23:08:55 +0800 Subject: [PATCH 3/6] =?UTF-8?q?CodeReader=E5=8F=AF=E4=BB=A5=E8=AF=BB?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E6=8C=87=E5=AE=9Acode=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E7=9A=84=E6=96=87=E4=BB=B6=EF=BC=8C=E4=BB=8E=E8=80=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E4=B8=8A=E4=BC=A0=E5=A4=A7=E9=87=8F=E6=BA=90=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/hy/java/uct/cdtocode/CDToCodeTracer.java | 8 ++++---- .../com/hy/java/uct/cdtocode/mapper/InitialMapper.java | 6 +++++- .../java/com/hy/java/uct/cdtocode/reader/CodeReader.java | 8 ++++---- src/main/resources/cdtocode/code/code path | 1 + 4 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/cdtocode/code/code path diff --git a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java index ca4b917..de1306a 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java +++ b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java @@ -34,18 +34,18 @@ public class CDToCodeTracer { // 读取完UML图识别结果后,将实体信息保存在classes_in_CD里 Map classes_in_CD = CDReader.read(cd_dir + "cd-eclipse_jetty.txt"); // 检查读取结果,可注释掉 - CDReader.check(classes_in_CD); + // CDReader.check(classes_in_CD); /* * 2、读取文档信息 */ DocReader.read(doc_dir + "basic-architecture.adoc"); /* - * 3、读取code目录下所有java文件 + * 3、读取code path指定的目录下所有java文件 */ - CodeReader.read(code_dir); + CodeReader.read(code_dir + "code path"); /* * 4、遍历模型中的实体元素(类或对象),针对每个元素,在code中寻找能匹配的java文件 */ - InitialMapper.map(); + InitialMapper.map(classes_in_CD); } } diff --git a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java index dbde150..02d666a 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java +++ b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java @@ -1,8 +1,12 @@ package com.hy.java.uct.cdtocode.mapper; +import java.util.Map; + +import com.hy.java.uct.umlrecog.util.UMLClass; + public class InitialMapper { - public static void map() { + public static void map(Map classes_in_CD) { // TODO Auto-generated method stub } diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java index ae2dd33..c8312fd 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java @@ -1,11 +1,11 @@ package com.hy.java.uct.cdtocode.reader; -import com.hy.java.utility.common.Traverser; -import com.hy.java.utility.common.Traverser.FileNode; +import com.hy.java.utility.common.FileEditor; public class CodeReader { - public static void read(String code_dir) { - FileNode code_dir_root = Traverser.traverseDir(code_dir); + public static void read(String code_path_file_path) { + FileEditor code_path_file = new FileEditor(code_path_file_path); + System.out.println(code_path_file.readFileToString()); } } diff --git a/src/main/resources/cdtocode/code/code path b/src/main/resources/cdtocode/code/code path new file mode 100644 index 0000000..39b9e76 --- /dev/null +++ b/src/main/resources/cdtocode/code/code path @@ -0,0 +1 @@ +D:\eclipse-committers\jetty.project-jetty-9.4.41.v20210516 \ No newline at end of file -- Gitee From f4d6913b015400e95e2adaa1b59e6cc9ae908b17 Mon Sep 17 00:00:00 2001 From: chief Date: Thu, 27 May 2021 22:54:08 +0800 Subject: [PATCH 4/6] =?UTF-8?q?UML=E5=9B=BE=E5=92=8C=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=83=BD=E5=B7=B2=E8=AF=BB=E5=AE=8C=EF=BC=8C=E4=B8=8B=E4=B8=80?= =?UTF-8?q?=E6=AD=A5=E5=BC=80=E5=A7=8B=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hy/java/uct/cdtocode/CDToCodeTracer.java | 8 ++-- .../uct/cdtocode/mapper/InitialMapper.java | 8 ++-- .../java/uct/cdtocode/reader/CodeReader.java | 43 ++++++++++++++++++- .../java/uct/cdtocode/reader/DocReader.java | 4 +- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java index de1306a..3eb54b4 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java +++ b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java @@ -38,14 +38,16 @@ public class CDToCodeTracer { /* * 2、读取文档信息 */ - DocReader.read(doc_dir + "basic-architecture.adoc"); + String doc = DocReader.read(doc_dir + "basic-architecture.adoc"); /* * 3、读取code path指定的目录下所有java文件 */ - CodeReader.read(code_dir + "code path"); + Map java_files = CodeReader.read(code_dir + "code path"); + // 检查读取结果,可注释掉 + // CodeReader.check(java_files); /* * 4、遍历模型中的实体元素(类或对象),针对每个元素,在code中寻找能匹配的java文件 */ - InitialMapper.map(classes_in_CD); + InitialMapper.map(classes_in_CD, java_files, doc); } } diff --git a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java index 02d666a..0c83623 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java +++ b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java @@ -6,8 +6,10 @@ import com.hy.java.uct.umlrecog.util.UMLClass; public class InitialMapper { - public static void map(Map classes_in_CD) { - // TODO Auto-generated method stub - + /** + * 映射 + */ + public static void map(Map classes_in_CD, Map java_files, String doc) { + // 天,这个咋弄啊 } } diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java index c8312fd..28860a1 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java @@ -1,11 +1,50 @@ package com.hy.java.uct.cdtocode.reader; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + import com.hy.java.utility.common.FileEditor; +import com.hy.java.utility.common.Traverser; +import com.hy.java.utility.common.Traverser.FileNode; public class CodeReader { - public static void read(String code_path_file_path) { + public static Map read(String code_path_file_path) { + // 该Map保存所有遍历到的java文件,形式为 + Map result = new HashMap<>(); + // 读取配置文件 FileEditor code_path_file = new FileEditor(code_path_file_path); - System.out.println(code_path_file.readFileToString()); + // 配置文件指定的代码根目录所对应的FileNode。遍历其children下的java文件即可 + FileNode code_files_root = Traverser.traverseDir(code_path_file.readFileToString()); + // 遍历 + filterJavaFileFromFN(code_files_root, result); + return result; + } + + /** + * 递归遍历code_files_root下的所有java文件,以存在Map中 + */ + private static void filterJavaFileFromFN(FileNode code_files_root, Map java_files) { + if (code_files_root.children == null) { + if (code_files_root.path.endsWith(".java")) { + // 这里put的key其实可以是类全称 + java_files.put(code_files_root.path, code_files_root.path); + } + } else { + for (FileNode code_file_or_dir : code_files_root.children) { + filterJavaFileFromFN(code_file_or_dir, java_files); + } + } + } + + /** + * 检查一下是不是遍历了所有java文件 + */ + public static void check(Map java_files) { + Set class_names = java_files.keySet(); + for (String class_name : class_names) { + System.out.println(java_files.get(class_name)); + } } } diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java index 8437a1b..5e1f7ee 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/DocReader.java @@ -6,8 +6,8 @@ public class DocReader { /** * 读取文档信息 */ - public static void read(String doc_file_path) { + public static String read(String doc_file_path) { FileEditor doc_file = new FileEditor(doc_file_path); - System.out.println(doc_file.readFileToString()); + return doc_file.readFileToString(); } } -- Gitee From 0c02638895a3cf6246945c26884d3bece67c12e7 Mon Sep 17 00:00:00 2001 From: origin Date: Tue, 1 Jun 2021 14:24:42 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E3=80=82=E5=87=86=E5=A4=87=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E3=80=82classes=5Fin=5FCD=E7=9A=84=E9=94=AE?= =?UTF-8?q?=E5=80=BC=E5=AF=B9=EF=BC=9A<=E7=B1=BB=E5=90=8D=EF=BC=88?= =?UTF-8?q?=E5=9B=BE=E9=87=8C=E7=9A=84=E7=B1=BB=E5=90=8D=EF=BC=89,?= =?UTF-8?q?=E7=B1=BB=E5=AF=B9=E8=B1=A1=EF=BC=88UMLClass=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=EF=BC=89>=EF=BC=9Bjava=5Ffiles=E7=9A=84=E9=94=AE=E5=80=BC?= =?UTF-8?q?=E5=AF=B9=EF=BC=9A<=E7=B1=BB=E5=85=A8=E7=A7=B0=EF=BC=88?= =?UTF-8?q?=E5=8C=85+=E7=B1=BB=E5=90=8D=EF=BC=89,java=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=EF=BC=88=E5=8F=AF=E7=94=A8javaparser?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=96=87=E4=BB=B6=E5=86=85=E5=AE=B9=EF=BC=89?= =?UTF-8?q?>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hy/java/uct/cdtocode/CDToCodeTracer.java | 4 +++ .../uct/cdtocode/mapper/InitialMapper.java | 16 +++++++++-- .../java/uct/cdtocode/reader/CodeReader.java | 27 ++++++++++++++++--- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java index 3eb54b4..a6eb3f7 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java +++ b/src/main/java/com/hy/java/uct/cdtocode/CDToCodeTracer.java @@ -47,6 +47,10 @@ public class CDToCodeTracer { // CodeReader.check(java_files); /* * 4、遍历模型中的实体元素(类或对象),针对每个元素,在code中寻找能匹配的java文件 + * + * 基于启发式模糊匹配的UML类图与代码追踪方法:首先针对类图中的类和代码中的类,基于类的名称进行字符串完全匹配,从而建立确定的初始追踪;基于同义词、 + * 词缀词典等语料库,定义基于类名称匹配和关联关系的启发式匹配规则,研究基于模糊匹配技术的追踪关系建立方法,基于初始追踪和启发式规则, + * 对类名不一致的模型和代码元素进行启发式追踪,扩展初始追踪关系。 */ InitialMapper.map(classes_in_CD, java_files, doc); } diff --git a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java index 0c83623..682524d 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java +++ b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java @@ -1,15 +1,27 @@ package com.hy.java.uct.cdtocode.mapper; import java.util.Map; +import java.util.Set; import com.hy.java.uct.umlrecog.util.UMLClass; public class InitialMapper { /** - * 映射 + * 首先针对类图中的类和代码中的类,基于类的名称进行字符串完全匹配,从而建立确定的初始追踪; + * + * 基于同义词、词缀词典等语料库,定义基于类名称匹配和关联关系的启发式匹配规则,研究基于模糊匹配技术的追踪关系建立方法,基于初始追踪和启发式规则, + * 对类名不一致的模型和代码元素进行启发式追踪,扩展初始追踪关系 + * + * classes_in_CD的键值对:<类名(图里的类名),类对象(UMLClass对象)> + * + * java_files的键值对:<类全称(包+类名),java文件地址(可用javaparser解析文件内容)> */ public static void map(Map classes_in_CD, Map java_files, String doc) { - // 天,这个咋弄啊 + Set key_set = classes_in_CD.keySet(); + for (String key : key_set) { + UMLClass UML_class = classes_in_CD.get(key); + System.out.println(UML_class.getTitle()); + } } } diff --git a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java index 28860a1..7ad057e 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java +++ b/src/main/java/com/hy/java/uct/cdtocode/reader/CodeReader.java @@ -1,9 +1,15 @@ package com.hy.java.uct.cdtocode.reader; +import java.io.File; +import java.io.FileNotFoundException; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.Set; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.PackageDeclaration; import com.hy.java.utility.common.FileEditor; import com.hy.java.utility.common.Traverser; import com.hy.java.utility.common.Traverser.FileNode; @@ -18,7 +24,9 @@ public class CodeReader { // 配置文件指定的代码根目录所对应的FileNode。遍历其children下的java文件即可 FileNode code_files_root = Traverser.traverseDir(code_path_file.readFileToString()); // 遍历 + System.out.println("正在遍历" + code_files_root.path + "下的源码文件,请稍候..."); filterJavaFileFromFN(code_files_root, result); + System.out.println("已遍历完java文件"); return result; } @@ -28,8 +36,21 @@ public class CodeReader { private static void filterJavaFileFromFN(FileNode code_files_root, Map java_files) { if (code_files_root.children == null) { if (code_files_root.path.endsWith(".java")) { - // 这里put的key其实可以是类全称 - java_files.put(code_files_root.path, code_files_root.path); + // 过滤\src\test\下的文件 + if (!code_files_root.path.contains("\\src\\test\\")) { + // 这里put的key是类全称(包+类名) + try { + CompilationUnit cu = StaticJavaParser.parse(new File(code_files_root.path)); + Optional package_declaration = cu.getPackageDeclaration(); + if (!package_declaration.isEmpty()) { + java_files.put(package_declaration.get().getNameAsString() + "." + + code_files_root.path.substring(code_files_root.path.lastIndexOf("\\") + 1, code_files_root.path.lastIndexOf(".")), code_files_root.path); + } + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } } } else { for (FileNode code_file_or_dir : code_files_root.children) { @@ -44,7 +65,7 @@ public class CodeReader { public static void check(Map java_files) { Set class_names = java_files.keySet(); for (String class_name : class_names) { - System.out.println(java_files.get(class_name)); + System.out.println(class_name + "\t" + java_files.get(class_name)); } } } -- Gitee From b1dcfdaca8b49f0c5ce576173dd4cd37944f444b Mon Sep 17 00:00:00 2001 From: chief Date: Mon, 7 Jun 2021 21:20:54 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=B8=8B=E4=B8=80=E6=AD=A5=EF=BC=881?= =?UTF-8?q?=E6=98=AF2=E7=9A=84=E5=9F=BA=E7=A1=80=E3=80=822=E6=AF=941?= =?UTF-8?q?=E5=A5=BD=E5=81=9A=EF=BC=89=EF=BC=9A1=E3=80=81=EF=BC=88LOC72?= =?UTF-8?q?=EF=BC=89=E5=A4=84=E7=90=86=E4=B8=80=E4=B8=8B=E4=B8=A4=E4=B8=AA?= =?UTF-8?q?String=EF=BC=8C=E7=84=B6=E5=90=8E=E7=9C=8B=E5=AE=83=E4=BB=AC?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E7=9B=B8=E4=BC=BC=E3=80=822=E3=80=81?= =?UTF-8?q?=EF=BC=88LOC45=EF=BC=89=E7=84=B6=E5=90=8E=E9=92=88=E5=AF=B9UML?= =?UTF-8?q?=5Fclass=E7=9A=84=E6=AF=8F=E6=9D=A1out=5Frela=EF=BC=8C=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=85=B6target=5Fclass=EF=BC=8C=E7=9C=8Bpossible=5Fja?= =?UTF-8?q?va=5Ffiles=E4=B8=AD=E7=9A=84=E6=AF=8F=E4=B8=AA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=98=AF=E5=90=A6=E4=B9=9F=E6=9C=89out=5Frela?= =?UTF-8?q?=EF=BC=8C=E4=B8=94=E6=96=87=E4=BB=B6=E7=9A=84out=5Frela?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E6=96=87=E4=BB=B6=E4=B9=9F=E5=9C=A8target=5F?= =?UTF-8?q?class=E7=9A=84possible=5Fjava=5Ffiles=E4=B8=AD=E3=80=82?= =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=9C=89=EF=BC=8C=E5=88=99UML=5Fclass?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E5=88=B0=E8=AF=A5=E6=96=87=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E4=B8=94target=5Fclass=E6=98=A0=E5=B0=84=E5=88=B0=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9A=84out=5Frela=E7=9B=AE=E6=A0=87=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uct/cdtocode/mapper/InitialMapper.java | 72 +++++++++++++++++-- .../hy/java/uct/umlrecog/util/UMLClass.java | 15 +++- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java index 682524d..088c7de 100644 --- a/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java +++ b/src/main/java/com/hy/java/uct/cdtocode/mapper/InitialMapper.java @@ -8,20 +8,80 @@ import com.hy.java.uct.umlrecog.util.UMLClass; public class InitialMapper { /** - * 首先针对类图中的类和代码中的类,基于类的名称进行字符串完全匹配,从而建立确定的初始追踪; + * 针对类图中的类和代码中的类,基于同义词、词缀词典等语料于库,定义基类名称匹配和关联关系的启发式匹配规则,研究基于模糊匹配技术的追踪关系建立方法,解决类名不一致的模型和代码元素的追踪问题: + *

+ *

    + *
  • 1、针对类图中的每个类,基于类的名称、与代码中的类文件进行字符串模糊匹配,从源码文件中选出可能映射的文件,存在UML_class.possible_java_files中 * - * 基于同义词、词缀词典等语料库,定义基于类名称匹配和关联关系的启发式匹配规则,研究基于模糊匹配技术的追踪关系建立方法,基于初始追踪和启发式规则, - * 对类名不一致的模型和代码元素进行启发式追踪,扩展初始追踪关系 + *
  • 2、然后针对UML_class的每条out_rela,记录其target_class,看possible_java_files中的每个文件是否也有out_rela,且文件的out_rela目标文件也在target_class的possible_java_files中。如果有,则UML_class映射到该文件,且target_class映射到文件的out_rela目标文件。 * - * classes_in_CD的键值对:<类名(图里的类名),类对象(UMLClass对象)> + *
  • 3、in_rela同上。 + *
* - * java_files的键值对:<类全称(包+类名),java文件地址(可用javaparser解析文件内容)> + * @param classes_in_CD 键值对:<类名(图里的类名),类对象(UMLClass对象)> + * @param java_files 键值对:<类全称(包+类名),java文件地址(可用javaparser解析文件内容)> + * @param doc */ public static void map(Map classes_in_CD, Map java_files, String doc) { Set key_set = classes_in_CD.keySet(); + // 1、针对类图中的每个类,基于类的名称、与代码中的类文件进行字符串模糊匹配,从源码文件中选出可能映射的文件,存在UML_class.possible_java_files中 for (String key : key_set) { UMLClass UML_class = classes_in_CD.get(key); - System.out.println(UML_class.getTitle()); + // 对每个UML_class,根据其title,找java_files中类全称的类名与其相似的java文件 + Set java_file_set = java_files.keySet(); + for (String java_file_full_name : java_file_set) { + if (titleSimilarWithFile(UML_class.getTitle(), java_file_full_name.substring(java_file_full_name.lastIndexOf(".") + 1))) { + UML_class.possible_java_files.add(java_file_full_name); + } + } } + // 2、然后针对UML_class的每条out_rela,记录其target_class,看possible_java_files中的每个文件是否也有out_rela,且文件的out_rela目标文件也在target_class的possible_java_files中。如果有,则UML_class映射到该文件,且target_class映射到文件的out_rela目标文件。 + for (String key : key_set) { + UMLClass UML_class = classes_in_CD.get(key); + if (UML_class.possible_java_files.size() < 1) { + System.out.println(UML_class.getTitle() + "\t" + "没有映射"); + } else { + for (String possible_java_file : UML_class.possible_java_files) { + // 针对UML_class的每条out_rela... + // 针对UML_class的每条out_rela... + // 针对UML_class的每条out_rela... + // 针对UML_class的每条out_rela... + // 针对UML_class的每条out_rela... + // 针对UML_class的每条out_rela... + // 针对UML_class的每条out_rela... + // 针对UML_class的每条out_rela... + System.out.println(UML_class.getTitle() + "\t" + possible_java_file); + } + } + } + // 3、in_rela同上。 + } + + /** + * 对每个UML_class,根据其title,找java_files中类全称的类名与其相似的java文件 + */ + private static boolean titleSimilarWithFile(String UML_class_title, String java_file_name) { + // 如果两个String相等,则返回true + if (UML_class_title.equals(java_file_name)) { + return true; + } + // 如果两个String相似,则返回true + else { + // 处理一下两个String,然后看它们是否相似 + + // 处理处理处理处理处理处理 + // 处理处理处理处理处理处理 + // 处理处理处理处理处理处理 + // 处理处理处理处理处理处理 + // 处理处理处理处理处理处理 + // 处理处理处理处理处理处理 + // 处理处理处理处理处理处理 + // 判断处理后的两个String是否相似 + if (java_file_name.contains(UML_class_title)) { + return true; + } + } + // 如果两个String既不相等也不相似,则返回false + return false; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/UMLClass.java b/src/main/java/com/hy/java/uct/umlrecog/util/UMLClass.java index 19833da..abea332 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/UMLClass.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/UMLClass.java @@ -19,11 +19,22 @@ public class UMLClass { private String title; private String attris_str; private String methods_str; - // 从该class出发的关系 + /** + * 从该class出发的关系 + */ public List out_relas = new ArrayList<>(); - // 指向该class的关系 + /** + * 指向该class的关系 + */ public List in_relas = new ArrayList<>(); + /** + * java_files中类全称的类名与其相同的java文件 + * + * 从这些文件中去找真正的映射(由于抽象层次不同,所以可能不止一个java文件是真正的映射)。寻找时要参考关系网 + */ + public List possible_java_files = new ArrayList<>(); + public String getTitle() { return title; } -- Gitee