检测多个Jar包冲突的class

当一个项目使用的jar越来越多,代码经常在运行的时候抛出异常:java.lang.NoSuchMethodExceptionjava.lang.NoSuchFieldError,基本是存在多个jar包包含相同的class类文件导致的,运行期可能用的class没有该方法等。

 

一、思路

为了提前找到存在相同classjar包,我准备写一个小程序,由于是操作jar包等,需要用Java代码来处理,但写出来一般是一个class文件,使用者可能需要用命令行执行的方式来调用它,java的桌面程序我不擅长,于是想到了用.NET开发一个工具壳子,内部调用java代码的方式来执行,开始想到用.NET下的IKVM来处理jar包,它提供了java基础包的.NET实现。但加载它也会使程序增大几M。最后我换了个思路,代码由Java来编写,.NETjava命令的方式执行java编写的class文件,再把输出内容展现到.NET工具的界面上,这样也会大大减小工具的大小。

 

二、技术实现:

新增一个java的控制台程序,它有默认main方法入口,需要传递待分析的Jar包路径,参数是通过外界传入的,这里会从.net界面输入参数传递到javamain入口,如代码:

public static void main(String[] args) {

if(args.length < 1){

System.out.println("请输入jar包路径!");

return;

}

然后根据传入的args的路径,获取该路径下的所有jar包文件,然后轮询所有jar包,获取里面存在的class文件,然后把jar包和对应的class文件放到一个字典类里,轮询所有jar包后,就可以通过字典类获取存在一个class多个jar包的文件。字典类结构为:HashMap<String,HashSet<String>>,用class名称作为key,这里比如为com/apache/abc/demo.class,多个jar包的名称做为value,达到键唯一,值是集合的字典,方便后续从字典输出存在多个jar包值的class,结构如下:

Key

Value(HashSet)

org/apache/taglibs/standard/lang/jstl/ImplicitObjects.class

 

standard-1.1.2.jar

jstl-1.2.jar

...

...

...

 

主要实现代码如:

File file = new File(args[0]);

Map<String,HashSet<String> > jarMap = new HashMap<String,HashSet<String>>();

if(null != file &&  file.exists() && file.isDirectory()){

File[] jarFile = file.listFiles();

for(File f : jarFile){

if(f.isFile() && f.getName().endsWith(".jar")){

try {

JarFile jar = new JarFile(f);

Enumeration<JarEntry> enumJar = jar.entries();

while(enumJar.hasMoreElements()){

JarEntry je = enumJar.nextElement();

if(je.getName().endsWith(".class")){

if(jarMap.containsKey(je.getName())){

jarMap.get(je.getName()).add(f.getName());

}else{

HashSet<String> set = new HashSet<String>();

set.add(f.getName());

jarMap.put(je.getName(), set);

 

查找重复类代码如下:

for(String s : keys){

if(jarMap.get(s).size() > 1){

//存在重复

HashSet<String> hsfile = jarMap.get(s);

String sfiles = "";

for(String sf : hsfile){

sfiles = sfiles + sf + ",";

}

if(sfiles.length() > 1){

sfiles = sfiles.substring(0, sfiles.length() -1);

}

System.out.println(sfiles + "有重复类:" + s);

}

}

最后java程序输出

System.out.println("[[over]]");

这里的作用是打一个结束标记,.NET代码根据这个结束标记显示内容。

Java代码会把查找到的jar包和冲突的类输出到控制台,.NET可以根据执行后的控制台字符串稍作处理然后展现出来。.NET通过新启一个Process调用cmd执行命令的方式调用Java指令,代码如下:

        public static string RunCmd(string command)

        {

            System.Diagnostics.Process p = new System.Diagnostics.Process();

            p.StartInfo.FileName = "cmd.exe";

            p.StartInfo.UseShellExecute = false;        

            p.StartInfo.RedirectStandardInput = true;   

            p.StartInfo.RedirectStandardOutput = true;  

            p.StartInfo.RedirectStandardError = true;   

            p.StartInfo.CreateNoWindow = true;

            p.Start();

            p.StandardInput.WriteLine(command);       

            p.StandardInput.WriteLine("exit");

            string result = p.StandardOutput.ReadToEnd();        

            p.WaitForExit(); p.Close();

            return result;

        }

指令传入:java Checksame + “界面录入的路径”,软件界面如:

  

上面就完成了检测jar包存在多个class的问题,代码不复杂,换了一个实现思路帮助解决了实际问题。

 

 工具下载

原文地址:https://www.cnblogs.com/Lawson/p/2984343.html