【问题标题】:Find which class in which jar has a given serialVersionUID查找哪个 jar 中的哪个类具有给定的 serialVersionUID
【发布时间】:2010-09-16 13:06:54
【问题描述】:

当我得到一个 java.io.InvalidClassException 时,它给了我它想要的 serialVersionUID,以及它得到的 serialVersionUID。有没有一种简单的方法可以判断我的几十个 jar 中的哪一个使用了错误的 serialVersionUID?

更新:我应该提到我们的意图是同时更新所有内容,但我正在尝试调试我们构建和部署过程中的问题。

【问题讨论】:

  • JAR 不使用 serialVersionUID。上课。该类在错误消息中命名,因此您所要做的就是找到该类。
  • 而且这个问题实际上没有任何意义。没有什么可以阻止您对 JAR 文件中的每个类或整个企业使用相同的值,例如 1L。不清楚你在问什么。

标签: java serialversionuid


【解决方案1】:

处理这种麻烦的最好方法是同时更新服务器端和客户端的jar。这将保证双方的类版本相同,并且在序列化/反序列化时不会遇到麻烦。每次遇到此问题时跟踪串行 UID 并不能解决任何问题,只会浪费大量时间和资源。花一些时间并实施适当的部署/打包策略要好得多。

如果实在没有其他选择,可以编写一个工具,从每个 jar 中加载一个类(使用 URLClassLoader),然后使用java.io.ObjectStreamClass.getSerialVersionUID() 获取您需要的信息。

【讨论】:

    【解决方案2】:

    笨拙但有效

    我会使用逆向工程工具
    1) 解压罐子
    2) 在类文件树上运行,比如说,jad
    3) 在这个新的源代码树上运行 grep 或任何其他查找工具以查找串行版本 uid。

    【讨论】:

      【解决方案3】:

      对 jar 中的每个类使用来自 sun jdk 的 serialver 工具。

      【讨论】:

        【解决方案4】:

        请记住,各种 JVM/容器/类加载器组合对于应该从引导类路径和应用程序/webapp 类路径加载哪些类有不同的看法。

        由于 serialver 总是首先从 bootclasspath 加载,这很复杂,因此您可能需要使用 -J-Xbootclasspath 来模拟不同的行为:

        f=/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Classes/
        serialver -J-Xbootclasspath:.:$f/dt.jar:$f/classes.jar:$f/ui.jar javax.xml.namespace.QName
        

        另一种方法是使用javap,例如:

        javap -verbose -bootclasspath . javax.xml.namespace.QName | sed -n -e '/static.*serialVersionUID/{N;p;}'
        

        【讨论】:

          【解决方案5】:

          根据 SO 中的一些答案,我想出了一个实用程序来执行此操作。这是我的课。

          package jar;
          
          import java.io.File;
          import java.io.IOException;
          import java.io.ObjectStreamClass;
          import java.net.MalformedURLException;
          import java.net.URL;
          import java.net.URLClassLoader;
          import java.util.ArrayList;
          import java.util.Enumeration;
          import java.util.HashSet;
          import java.util.jar.JarEntry;
          import java.util.jar.JarFile;
          
          
          /**
           * Searches all the jars in a given directory for a class with the given UID.
           * Additional directories can be specified to support with loading the jars.  
           * For example, you might want to load the lib dir from your app server to get
           * the Servlet API, etc.  
           */
          public class JarUidSearch
          {
              public static void main(String args[])
                      throws IOException, ClassNotFoundException
              {
                  if( args.length < 2)
                  {
                      System.err.println("Usage: <UID to search for> <directory with jars to search> [additional directories with jars]");
                      System.exit(-1);
                  }
          
                  long targetUID = Long.parseLong(args[0]);
          
                  ArrayList<URL> urls = new ArrayList<URL>();
          
                  File libDir = new File(args[1]);
          
                  for (int i = 1; i < args.length; i++)
                  {
                      gatherJars(urls, new File(args[i]));
                  }
          
                  File[] files = libDir.listFiles();
          
                  for (File file : files)
                  {
                      try
                      {
                          checkJar(targetUID, urls, file);
                      }
                      catch(Throwable t)
                      {
                          System.err.println("checkJar for " + file + " threw: " + t);
                          t.printStackTrace();
                      }   
                  }
              }
          
              /**
               * 
               * @param urls
               * @param libDir
               * @throws MalformedURLException
               */
              public static void gatherJars(ArrayList<URL> urls, File libDir)
                      throws MalformedURLException
              {
                  File[] files = libDir.listFiles();
          
                  for (File file : files)
                  {
                      urls.add(file.toURL());
                  }
              }
          
              /**
               * 
               * @param urls
               * @param file
               * @throws IOException
               * @throws ClassNotFoundException
               */
              public static void checkJar(long targetUID, ArrayList<URL> urls, File file)
                      throws IOException, ClassNotFoundException
              {
                  System.out.println("Checking: " + file);
                  JarFile jarFile = new JarFile(file);
                  Enumeration allEntries = jarFile.entries();
                  while (allEntries.hasMoreElements())
                  {
                      JarEntry entry = (JarEntry) allEntries.nextElement();
                      String name = entry.getName();
          
                      if (!name.endsWith(".class"))
                      {
                          // System.out.println("Skipping: " + name);
                          continue;
                      }
          
                      try
                      {
                          URLClassLoader loader = URLClassLoader.newInstance((URL[]) urls.toArray(new URL[0]));
                          String className = name.substring(0,
                              name.length() - ".class".length()).replaceAll("/", ".");
                          Class<?> clazz = loader.loadClass(className);
                          ObjectStreamClass lookup = ObjectStreamClass.lookup(clazz);
          
                          if (lookup != null)
                          {
                              long uid = lookup.getSerialVersionUID();
          
                              if (targetUID == uid)
                              {
                                  System.out.println(file + " has class: " + clazz);
                              }
                          }
                      }
                      catch (Throwable e)
                      {
                          System.err.println("entry " + name + " caused Exception: " + e);
                      }
                  }
              }
          }
          

          【讨论】:

            【解决方案6】:

            我在 Linux 上使用这个命令来检查当前目录中的所有 Jars:

            find . -type f -name "*.jar" -exec sh -c 'javap -verbose -p -constants -cp {} com.myCompany.myClass | grep serialVersionUID' \;
            

            请记住,serialVersionUID 可能未在您的类中明确声明。在这种情况下,serialVersionUID 将在运行时计算,并且无法使用上面的 find 命令进行搜索。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-11-27
              • 2017-02-08
              • 1970-01-01
              • 2014-04-13
              • 1970-01-01
              • 2014-11-29
              相关资源
              最近更新 更多