最近因为因为web容器升级,而容器自带了很多jar,发现和应用中的jar有冲突(相同的类,不同的版本),导致出现NoSuchMethon异常什么的。需求来了,需要比较两个目录下有那些相同的类。这个需求前人已经写烂了,可上网搜索一时找不到合适的,就再写了一遍,并作下记录,方便后来人和将来的自己再用。
不多说,上代码(一次性代码,1小时搞定,如有编程风格问题,敬请谅解):
package com.mikegu.tools.jardiff; import java.io.File; import java.io.IOException; /** * 启动入口类 * * @author haiquan.guhq */ public class JarDiffMain { /** * 输入要比较的两个目录,目录下包含jar,结果输出到控制台。 */ public static void main(String[] args) throws IOException { if (args.length != 2) { System.out.println("please input two compare dirs"); System.exit(1); } String firstInputPath = args[0]; String secondInputPath = args[1]; File file = new File(firstInputPath); File[] listFiles = file.listFiles(); for (File oneFile : listFiles) { if (oneFile.isFile() && oneFile.getAbsolutePath().endsWith(".jar")) { String jarName = oneFile.getName(); ZipDecompression.decompression(oneFile.getAbsolutePath(), firstInputPath + "/tmp/" + jarName); // 解压 ClassNameFinder.find(jarName, firstInputPath + "/tmp/" + jarName, 1); // 查找 } } file = new File(secondInputPath); listFiles = file.listFiles(); for (File oneFile : listFiles) { if (oneFile.isFile() && oneFile.getAbsolutePath().endsWith(".jar")) { String jarName = oneFile.getName(); ZipDecompression.decompression(oneFile.getAbsolutePath(), secondInputPath + "/tmp/" + jarName); ClassNameFinder.find(jarName, secondInputPath + "/tmp/" + jarName, 2); } } ClassNameFinder.compare(); } }
package com.mikegu.tools.jardiff; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; /** * 搜索和比较相同的类 */ public class ClassNameFinder { private static Map<String, List<ClassInfosDO>> firstMap = new HashMap<String, List<ClassInfosDO>>(); private static Map<String, List<ClassInfosDO>> secondMap = new HashMap<String, List<ClassInfosDO>>(); public static void find(String jarName, String path, int order) { List<String> allClassName = new ArrayList<String>(); //根据路径取得全类 getAllClassName(path, allClassName, path.length() + 1); if (allClassName != null) { for (String one : allClassName) { ClassInfosDO classInfosDO = new ClassInfosDO(one, jarName); List<ClassInfosDO> list = getOrderMap(order).get(one); if (list == null) { List<ClassInfosDO> arrayList = new ArrayList<ClassInfosDO>(); arrayList.add(classInfosDO); getOrderMap(order).put(one, arrayList); } else { list.add(classInfosDO); } } } } public static void compare() { Set<String> keySet = firstMap.keySet(); List<String> keyList = new ArrayList<String>(); keyList.addAll(keySet); Collections.sort(keyList); Map<String, List<String>> jarViewResult = new TreeMap<String, List<String>>(); List<String> classViewResult = new ArrayList<String>(); for (String fullClassName : keyList) { List<ClassInfosDO> list = secondMap.get(fullClassName); if (list != null) { //目录1 StringBuffer input1SB = new StringBuffer(); List<ClassInfosDO> value = firstMap.get(fullClassName); for (ClassInfosDO oneClassInfosDO : value) { input1SB.append(" " + oneClassInfosDO.getJarName() + ","); } //目录2 StringBuffer input2SB = new StringBuffer(); for (ClassInfosDO oneClassInfosDO : list) { input2SB.append(" " + oneClassInfosDO.getJarName() + ","); } classViewResult.add(fullClassName + "\tInput1: " + input1SB.toString() + "\t input2: " + input2SB.toString()); String jarKey = input1SB.toString() + " vs " + input2SB.toString(); if (jarViewResult.get(jarKey) != null) { jarViewResult.get(jarKey).add(fullClassName); } else { List<String> classes = new ArrayList<String>(); classes.add(fullClassName); jarViewResult.put(jarKey, classes); } } } writeResult(jarViewResult, classViewResult); } /** * 从jar的纬度和class的纬度分别输出结果 */ private static void writeResult(Map<String, List<String>> jarViewResult, List<String> classViewResult) { System.out.println("View From jar start....."); System.out.println("Total conflict jar num is " + jarViewResult.size()); Set<Entry<String, List<String>>> entrySet = jarViewResult.entrySet(); for (Entry<String, List<String>> one : entrySet) { String key = one.getKey(); System.out.println("conflict jar name is" + key); for (String oneClassName : one.getValue()) { System.out.println("\t\t" + oneClassName); } System.out.println(); } System.out.println("View From jar end!!!!"); System.out.println("View From class start....."); System.out.println("Total conflict class num is " + classViewResult.size()); for (String abc : classViewResult) { System.out.println(abc); } System.out.println("View From class end!!!!"); } public static Map<String, List<ClassInfosDO>> getOrderMap(int order) { if (order == 1) { return firstMap; } else { return secondMap; } } public static void getAllClassName(String dir, List<String> allClassName, int length) { File file = new File(dir); File[] listFiles = file.listFiles(); if (listFiles == null || listFiles.length == 0) { return; } for (File oneFile : listFiles) { String absolutePath = oneFile.getAbsolutePath(); if (oneFile.isDirectory()) { getAllClassName(absolutePath, allClassName, length); } else { if (absolutePath.endsWith(".class")) { allClassName.add(absolutePath.substring(length)); } } } } // public static void main(String[] args) { // List<String> allClassName = new ArrayList<String>(); // getAllClassName("/tmp/1", allClassName, "/tmp/1".length() + 1); // System.out.println(allClassName); // System.out.println(allClassName.size()); // // } }
package com.mikegu.tools.jardiff; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class ZipDecompression { // public static void main(String[] args) throws IOException { // String fileName = "toolkit.common.lang-1.0-sources.jar"; // decompression("C:/" + fileName, "C:/test"); // } public static void decompression(String zipFile, String destination) throws IOException { ZipFile zip; try { zip = new ZipFile(zipFile); } catch (IOException e) { System.out.println("error name " + zipFile); throw e; } Enumeration en = zip.entries(); ZipEntry entry = null; byte[] buffer = new byte[8192]; int length = -1; InputStream input = null; BufferedOutputStream bos = null; File file = null; while (en.hasMoreElements()) { entry = (ZipEntry) en.nextElement(); if (entry.isDirectory()) { continue; } input = zip.getInputStream(entry); file = new File(destination, entry.getName()); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } bos = new BufferedOutputStream(new FileOutputStream(file)); while (true) { length = input.read(buffer); if (length == -1) break; bos.write(buffer, 0, length); } bos.close(); input.close(); } zip.close(); } }
package com.mikegu.tools.jardiff; /** * 类信息DO */ public class ClassInfosDO { private String classFullName; private String jarName; /** * @param classFullName * @param jarName */ public ClassInfosDO(String classFullName, String jarName) { this.classFullName = classFullName; this.jarName = jarName; } /** * @return the classFullName */ public String getClassFullName() { return classFullName; } /** * @param classFullName the classFullName to set */ public void setClassFullName(String classFullName) { this.classFullName = classFullName; } /** * @return the jarName */ public String getJarName() { return jarName; } /** * @param jarName the jarName to set */ public void setJarName(String jarName) { this.jarName = jarName; } }