查找哪个jar 中的哪个类具有给定的serialVersionUID

发布于 2024-07-06 07:57:04 字数 217 浏览 9 评论 0原文

当我收到 java.io.InvalidClassException 时,它会为我提供它想要的serialVersionUID 以及它获得的serialVersionUID。 有没有一种简单的方法来判断我的几十个罐子中的哪一个使用了错误的serialVersionUID?

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

When I get a java.io.InvalidClassException, it gives me the serialVersionUID that it wants, and the serialVersionUID that it got. Is there an easy way to tell which of my dozens of jars using the wrong serialVersionUID?

Update: I should mention that our intention is to update everything at the same time, but I'm trying to debug a problem in our build and deploy process.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

空城旧梦 2024-07-13 07:57:04

对 jar 中的每个类使用 sun jdk 中的 Serialver 工具。

use the serialver tool from the sun jdk for each class in the jar.

心是晴朗的。 2024-07-13 07:57:04

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

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

The best way to deal with this kind of trouble is to update jars on the server and client side at the same time. This will guarantee the same version of your classes on both sides and you'll not have trouble when serializing / deserializing. Tracking serial UIDs each time you have this problem is not going to solve anything, you're only going to waste considerable time and resources. Its much better to spend some time and implement a proper deployment / packaging strategy.

If you really don't have any other choice, you can write a tool that loads a class from each jar (using a URLClassLoader) and then use java.io.ObjectStreamClass.getSerialVersionUID() to obtain the information you need.

许久 2024-07-13 07:57:04

请记住,各种 JVM/容器/类加载器组合对于应该从 bootclasspath 与 application/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;}'

Bear in mind that various JVM/container/classloader combinations have different opinions on which classes should be loaded from the bootclasspath versus the application/webapp classpath.

This is complicated by the fact that serialver always loads from the bootclasspath first, so you may need to use -J-Xbootclasspath as below, to simulate different behaviour:

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

Another approach is to use javap, for example:

javap -verbose -bootclasspath . javax.xml.namespace.QName | sed -n -e '/static.*serialVersionUID/{N;p;}'
满地尘埃落定 2024-07-13 07:57:04

根据 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);
            }
        }
    }
}

I came up with a utility to perform this, based on some answers in SO. Here's my class.

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);
            }
        }
    }
}
寄风 2024-07-13 07:57:04

笨拙但有效

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

clumsy but works

i would use a reverse engineering tool
1) unzip the jars
2) run, say, jad on the class file tree
3) run grep or any other find tool on this new tree of source to look for the serial version uid.

神经暖 2024-07-13 07:57:04

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

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

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

I was using this command on Linux to examine all Jars in current directory:

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

Please bear in mind that serialVersionUID might be not declared in your class explicitly. In that case serialVersionUID will be calculated at runtime and cannot be searched for using find command above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文