Header Ads Widget

Responsive Advertisement

how to find out Jar Difference



To find the difference between two Java JAR files, you can use various methods and tools to compare their contents. Here are a few approaches:

1. Using jar command-line tool (shipped with JDK):

You can extract the contents of both JAR files and then compare the extracted directories.

Steps:

Ø  Extract the contents of the JAR files:

Bash

jar -xf file1.jar

jar -xf file2.jar

 

Ø  Use a file comparison tool to compare the extracted directories:

bash

diff -r dir1 dir2

 

This will show differences in files and subdirectories between the two JARs.

2. Using jardiff Tool (from Apache):

jardiff is a simple command-line tool used to compare two JAR files and output their differences.

Steps:

Ø  Install and run jardiff:

Bash

java -jar jardiff.jar file1.jar file2.jar

 

Ø  It will provide a detailed report of differences, including added, removed, and changed files.

3. Using JAR Compare Plugin in IDEs:

Many IDEs like IntelliJ IDEA and Eclipse offer plugins or built-in features to compare JAR files.

In IntelliJ:

Ø  Open the Project View.

Ø  Select the two JAR files.

Ø  Right-click and choose "Compare Archives."

This will show differences in class files, resources, and even method-level changes.

4. Using Beyond Compare or WinMerge:

If you want a graphical interface, tools like Beyond Compare or WinMerge allow you to compare JARs (which are essentially zip files).

Steps:

Ø  Open the tool.

Ø  Load both JAR files for comparison.

Ø  These tools will highlight the differences in the classes, manifest files, etc.

5. Using jarsigner and javap:

For more granular comparisons, you can extract the bytecode from the JARs and compare them:

Ø  Use jarsigner to verify signatures:

bash

jarsigner -verify -verbose file1.jar

jarsigner -verify -verbose file2.jar

 

Ø  Use javap to disassemble class files:

Bash

javap -c -verbose classFile1.class > classFile1.txt

javap -c -verbose classFile2.class > classFile2.txt

 

Ø  Then, compare the .txt files to see method-level or bytecode differences.

 

6. Java utility that analyzes and compare two jar files:

 

package com.kartik;

 

import java.io.FileInputStream;

 

import java.util.ArrayList;

 

import java.util.HashMap;

 

import java.util.HashSet;

 

import java.util.List;

 

import java.util.Map;

 

import java.util.Set;

 

import java.util.TreeSet;

 

import java.util.jar.Attributes;

 

import java.util.jar.JarEntry;

 

import java.util.jar.JarInputStream;

 

import java.util.jar.Manifest;

 

import org.objectweb.asm.ClassReader;

 

import org.objectweb.asm.Opcodes;

 

import org.objectweb.asm.Type;

 

import org.objectweb.asm.tree.ClassNode;

 

import org.objectweb.asm.tree.MethodNode;

 

public class Demo {

 

 static Map<String, Set<String>> mapOld = new HashMap<String, Set<String>>();

 

 static Map<String, Set<String>> mapNew = new HashMap<String, Set<String>>();

 

 /**

  *

  * @param setA

  * @param setB

  * @return

  */

 public static Set<String> union(Set<String> setA, Set<String> setB) {

 

  Set<String> tmp = new TreeSet<String>(setA);

 

  tmp.addAll(setB);

 

  return tmp;

 

 }

 

 /**

  *

  * @param setA

  * @param setB

  * @return

  */

 public static Set<String> intersection(Set<String> setA, Set<String> setB) {

 

  Set<String> tmp = new TreeSet<String>();

 

  for (String x : setA)

 

   if (setB.contains(x))

 

    tmp.add(x);

 

  return tmp;

 

 }

 

 /**

  *

  * @param setA

  * @param setB

  * @return

  */

 public static Set<String> difference(Set<String> setA, Set<String> setB)

 

 {

 

  Set<String> tmp = new TreeSet<String>(setA);

 

  tmp.removeAll(setB);

 

  return tmp;

 

 }

 

 /**

  *

  * @param setA

  * @param setB

  * @return

  */

 public static Set<String> symDifference(Set<String> setA, Set<String> setB) {

 

  Set<String> tmpA;

 

  Set<String> tmpB;

 

  tmpA = union(setA, setB);

 

  tmpB = intersection(setA, setB);

 

  return difference(tmpA, tmpB);

 

 }

 

 /**

  *

  * @param jarFileList

  */

 public void getClassNamesFromJar(List<String> jarFileList) {

 

  int count = 0;

 

  for (String string : jarFileList) {

 

   count++;

 

   String jarFileName = string;

 

   System.out.println("Jar File Name: " + jarFileName);

 

   System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -");

 

   try {

 

    JarInputStream jarFile = new JarInputStream(

 

    new FileInputStream(jarFileName));

 

    JarEntry entry;

 

    Manifest m = jarFile.getManifest();

 

    Attributes atts = m.getMainAttributes();

 

    for (Map.Entry<Object, Object> entrys : atts.entrySet()) {

 

     System.out.println(entrys.getKey() + "-->>>> " +

 

     entrys.getValue());

 

    }

 

    while (true) {

 

     entry = jarFile.getNextJarEntry();

 

     if (entry == null) {

 

      break;

 

     }

 

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

 

      ClassNode classNode = new ClassNode();

 

      try {

 

       ClassReader classReader = new

 

       ClassReader(jarFile);

 

       classReader.accept(classNode, 0);

 

      } catch (Exception e3) {

 

       jarFile.close();

 

      }

 

      describeClass(classNode, count);

 

      //

 

      System.out.println(describeClass(classNode, count));

 

     }

 

    }

 

   } catch (Exception e) {

 

    System.out

      .println("Oops.. Encounter an issue while parsing jar"

        + e.toString());

 

   }

 

  }

 

 }

 

 /**

  *

  * @param classNode

  * @param count

  * @return

  */

 public String describeClass(ClassNode classNode, int count) {

 

  StringBuilder classDescription = new StringBuilder();

 

  Type classType = Type.getObjectType(classNode.name);

 

  if ((classNode.access & Opcodes.ACC_PUBLIC) != 0) {

 

   classDescription.append("public ");

 

  }

 

  if ((classNode.access & Opcodes.ACC_PRIVATE) != 0) {

 

   classDescription.append("private ");

 

  }

 

  if ((classNode.access & Opcodes.ACC_PROTECTED) != 0) {

 

   classDescription.append("protected ");

 

  }

 

  if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {

 

   classDescription.append("abstract ");

 

  }

 

  if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) {

 

   classDescription.append("interface ");

 

  } else {

 

   classDescription.append("class ");

 

  }

 

  classDescription.append(classType.getClassName()).append("\n");

 

  classDescription.append("{\n");

 

  // The method signatures (e.g. -

 

  // "public static void main(String[]) throws Exception")

 

  @SuppressWarnings("unchecked")

  List<MethodNode> methodNodes = classNode.methods;

 

  Set<String> methodHold = new HashSet<String>();

 

  for (MethodNode methodNode : methodNodes) {

 

   String methodDescription = describeMethod(methodNode);

 

   methodHold.add(methodDescription);

 

   classDescription.append("\t").append(methodDescription)

 

   .append("\n");

 

  }

 

  if (count % 2 == 0) {

 

   mapOld.put(classType.getClassName(), methodHold);

 

  } else {

 

   mapNew.put(classType.getClassName(), methodHold);

 

  }

 

  classDescription.append("}\n");

 

  return classDescription.toString();

 

 }

 

 /**

  *

  * @param methodNode

  * @return

  */

 public String describeMethod(MethodNode methodNode) {

 

  StringBuilder methodDescription = new StringBuilder();

 

  Type returnType = Type.getReturnType(methodNode.desc);

 

  Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);

 

  @SuppressWarnings("unchecked")

  List<String> thrownInternalClassNames = methodNode.exceptions;

 

  if ((methodNode.access & Opcodes.ACC_PUBLIC) != 0) {

 

   methodDescription.append("public ");

 

   // }

 

   /*

    *

    * if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0) {

    *

    * methodDescription.append("private "); }

    *

    *

    *

    * if ((methodNode.access & Opcodes.ACC_PROTECTED) != 0) {

    *

    * methodDescription.append("protected "); }

    *

    *

    *

    * if ((methodNode.access & Opcodes.ACC_STATIC) != 0) {

    *

    * methodDescription.append("static "); }

    *

    *

    *

    * if ((methodNode.access & Opcodes.ACC_ABSTRACT) != 0) {

    *

    * methodDescription.append("abstract "); }

    *

    *

    *

    * if ((methodNode.access & Opcodes.ACC_SYNCHRONIZED) != 0)

    *

    * {

    *

    * methodDescription.append("synchronized "); }

    */

 

   methodDescription.append(returnType.getClassName());

 

   methodDescription.append(" ");

 

   methodDescription.append(methodNode.name);

 

   methodDescription.append("(");

 

   for (int i = 0; i < argumentTypes.length; i++) {

 

    Type argumentType = argumentTypes[i];

 

    if (i > 0) {

 

     methodDescription.append(", ");

 

    }

 

    methodDescription.append(argumentType.getClassName());

 

   }

 

   methodDescription.append(")");

 

   /*

    *

    * if (!thrownInternalClassNames.isEmpty()) {

    *

    * methodDescription.append(" throws "); int i = 0; for

    *

    * (String

    *

    * thrownInternalClassName : thrownInternalClassNames) { if

    *

    * (i > 0)

    *

    * { methodDescription.append(", "); }

    *

    * methodDescription.append(Type.

    *

    * getObjectType(thrownInternalClassName).getClassName());

    *

    * i++; } }

    */

 

  }

 

  return methodDescription.toString();

 

 }

 

 public static void main(String[] args) {

 

  Demo d = new Demo();

 

  List<String> jarFileName = new ArrayList<String>();

 

  jarFileName.add("D:\\External_Jar\\Compare\\old\\XmlSchema-1.4.2.jar");

 

  jarFileName

    .add("D:\\External_Jar\\Compare\\new\\xmlschema-core- 2.2.1.jar");

 

  d.getClassNamesFromJar(jarFileName);

 

  /*

   *

   * boolean flag=false; StringBuilder classDescription = new

   *

   * StringBuilder(); for (Map.Entry<String, Set<String>> entryOld :

   *

   * mapOld.entrySet()) { for (Map.Entry<String, Set<String>>

   *

   * entryNew :

   *

   * mapNew.entrySet()) {

   *

   * if(entryOld.getKey().equalsIgnoreCase(entryNew.getKey())){

   *

   * flag=true;

   *

   * } } if(!flag){

   *

   * classDescription.append("Add new Class in latest Jar "

   *

   * +entryOld.getKey()).append("\n");

   *

   * classDescription.append("{\n");

   *

   * //System.out.println("-- -- -- -- New-- -- -- -- -- -

   *

   * "+entryOld.getKey()+

   *

   * "-- -- -- -- -- -- -- -- -- -- "); Set<String>

   * val=entryOld.getValue();

   *

   * for

   *

   * (String string : val) {

   *

   * classDescription.append("\t").append(string).append("\n");

   *

   * //System.out.println(string); } classDescription.append("}\n");

   *

   * }else{ flag=false; } }

   *

   * System.out.println(classDescription.toString());

   */

 

  System.out.println();

 

  StringBuilder classDescriptionSecond = new StringBuilder();

 

  boolean falgVal = false;

 

  System.out

    .println("-#############################################################-");

 

  System.out

    .println("Remove Some Class in latest jar that list give below:");

 

  System.out

    .println("-#############################################################-");

 

  int i = 0;

 

  for (Map.Entry<String, Set<String>> entryNew : mapNew.entrySet())

 

  {

 

   for (Map.Entry<String, Set<String>> entryOld :

 

   mapOld.entrySet()) {

 

    if

 

    (entryOld.getKey().equalsIgnoreCase(entryNew.getKey())) {

 

     falgVal = true;

 

    }

 

   }

 

   if (!falgVal) {

 

    classDescriptionSecond.append(i + " " +

 

    entryNew.getKey())

 

    .append("\n");

 

    classDescriptionSecond.append("{\n");

 

    Set<String> val = entryNew.getValue();

 

    for (String string : val) {

 

     classDescriptionSecond.append("\t").append(string)

 

     .append("\n");

 

    }

 

    classDescriptionSecond.append("}\n");

 

    i++;

 

   } else {

 

    falgVal = false;

 

   }

 

  }

 

  System.out.println(classDescriptionSecond.toString());

 

  System.out.println();

 

  System.out

    .println("-#############################################################-");

 

  System.out

    .println("Matches Class in latest and old but some method have changes:");

 

  System.out

 

    .println("###############################################################-");

 

  StringBuilder classDescriptionThird = new StringBuilder();

 

  int j = 0;

 

  for (Map.Entry<String, Set<String>> entryNew : mapNew.entrySet())

 

  {

 

   for (Map.Entry<String, Set<String>> entryOld :

 

   mapOld.entrySet()) {

 

    if

 

    (entryOld.getKey().equalsIgnoreCase(entryNew.getKey())) {

 

     classDescriptionThird.append(j + " " +

 

     entryNew.getKey())

 

     .append("\n");

 

     classDescriptionThird.append("{\n");

 

     Set<String> valOld = entryOld.getValue();

 

     Set<String> valNew = entryNew.getValue();

 

     Set<String> temp = intersection(valOld,

 

     valNew);

 

     Set<String> addMethodInLatest =

 

     difference(valOld, temp);

 

     Set<String> removeMethodInLatest =

 

     difference(valNew, temp);

 

     for (String string : removeMethodInLatest) {

 

      classDescriptionThird

 

      .append("\t")

 

      .append("Update/remove old method in Latest Jar ->")

 

      .append(string).append("\n");

 

     }

 

     /*

      *

      * this is need to display of how many new

      *

      * method add for

      *

      * (String string : addMethodInLatest) {

      *

      * classDescriptionThird

      *

      * .append("\t").append("Add new method in

      *

      * Latest Jar -- >"

      *

      * ).append(string).append("\n"); }

      */

 

     classDescriptionThird.append("}\n");

 

     j++;

 

    }

 

   }

 

  }

 

  System.out.println(classDescriptionThird.toString());

 

 }

 

}

 

 

 

This Java code is a utility that analyzes and compares two JAR files, focusing on the classes and methods contained within them. The primary purpose is to identify differences between the two versions of the JAR files.

Key Components:

  1. Utility Methods:

Ø  union, intersection, difference, symDifference: These methods are used to perform set operations on the collections of methods or classes from the JAR files.

  1. getClassNamesFromJar Method:

Ø  This method takes a list of JAR files, reads the class entries, and parses them using ASM (a Java bytecode manipulation framework).

Ø  It gathers the classes and methods from the JAR file, storing them in maps (mapOld for the old version and mapNew for the new version).

  1. describeClass Method:

Ø  This method describes the class, including its access modifiers and methods, and populates the appropriate map depending on whether it is analyzing the old or new JAR.

  1. describeMethod Method:

Ø  This method formats and returns the method's signature, including its access modifiers, return type, and parameter types.

  1. Comparison Logic:

Ø  The main method of the Demo class compares the contents of the two maps (mapOld and mapNew) to determine:

ü  Which classes are present in the new JAR but not in the old one.

ü  Which classes are present in both but have different methods.

ü  It also identifies methods that have been removed or added.

Example of Usage:

The main method sets up the analysis by comparing two specific JAR files (XmlSchema-1.4.2.jar and xmlschema-core-2.2.1.jar), then runs the comparison, outputting the differences.

Execution Flow:

  1. Parsing JAR Files:

Ø  The getClassNamesFromJar method parses the JAR files and extracts class information into maps.

  1. Comparing Classes:

Ø  Classes that exist in the new JAR but not in the old one are listed.

Ø  Classes that exist in both but have different methods are identified, and the differences are described.

Output:

The program prints out:

  • Classes that were removed or added.
  • Methods that were updated or removed in classes that exist in both versions.

Notes:

  • The code uses ASM to read and manipulate class files, which is common for tasks like bytecode analysis and modification.
  • Error handling could be improved for robustness, especially around the file handling and ASM operations.

If you need to run this code, ensure you have the ASM library included in your classpath, and adjust the file paths for the JAR files you wish to compare.

 

 


the difference between two Java JAR files
the difference between two Java JAR files







Post a Comment

0 Comments