当我得到一个java.io.InvalidClassException时,它给了我想要的serialVersionUID,以及它得到的serialVersionUID。有没有一种简单的方法可以使用错误的serialVersionUID来判断我的几十个罐子中的哪一个?
更新:我应该提一下,我们的目的是同时更新所有内容,但我正在尝试在构建和部署过程中调试问题。
答案 0 :(得分:5)
使用sun jdk中的serialver工具为jar中的每个类。
答案 1 :(得分:2)
解决此类问题的最佳方法是同时更新服务器端和客户端端的jar。这将保证双方的同一版本的类,并且在序列化/反序列化时不会遇到麻烦。每次遇到此问题时跟踪串行UID都无法解决任何问题,您只会浪费大量时间和资源。花更多时间并实施适当的部署/打包策略要好得多。
如果您真的没有其他选择,可以编写一个工具从每个jar中加载一个类(使用URLClassLoader),然后使用java.io.ObjectStreamClass.getSerialVersionUID()
获取所需的信息。
答案 2 :(得分:2)
请记住,各种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;}'
答案 3 :(得分:2)
根据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);
}
}
}
}
答案 4 :(得分:1)
笨拙但有效
我会使用逆向工程工具
1)解压罐子
2)在类文件树上运行,比方说,jad
3)在这个新的源代码树上运行grep或任何其他查找工具,以查找序列版本uid。
答案 5 :(得分:0)
我在 Linux 上使用此命令检查当前目录中的所有 Jars:
find . -type f -name "*.jar" -exec sh -c 'javap -verbose -p -constants -cp {} com.myCompany.myClass | grep serialVersionUID' \;
请记住,serialVersionUID 可能未在您的类中明确声明。在这种情况下,serialVersionUID 将在运行时计算,无法使用上面的 find 命令进行搜索。