Question

Lorsque j’obtiens une exception java.io.InvalidClassException, elle me donne le numéro de série serialVersionUID qu’il veut et le numéro de série serialVersionUID qu’il a reçu. Existe-t-il un moyen facile de déterminer lequel de mes dizaines de fichiers jar utilise le mauvais serialVersionUID?

Mise à jour : je devrais mentionner que notre intention est de tout mettre à jour en même temps, mais j'essaie de résoudre un problème dans notre processus de création et de déploiement.

Était-ce utile?

La solution

utilisez l'outil serialver du sun jdk pour chaque classe du pot.

Autres conseils

Le meilleur moyen de résoudre ce type de problème est de mettre à jour les fichiers JAR côté serveur et côté client en même temps. Cela garantira la même version de vos classes des deux côtés et vous ne rencontrerez aucun problème lors de la sérialisation / désérialisation. Suivre les UID en série chaque fois que vous rencontrez ce problème ne résoudra rien, vous allez simplement perdre un temps et des ressources considérables. Il est bien mieux de passer du temps à mettre en œuvre une stratégie de déploiement / conditionnement appropriée.

Si vous n'avez vraiment pas d'autre choix, vous pouvez écrire un outil qui charge une classe à partir de chaque fichier jar (à l'aide d'un chargeur URLClassLoader), puis utiliser java.io.ObjectStreamClass.getSerialVersionUID () pour obtenir les informations dont vous avez besoin.

N'oubliez pas que différentes combinaisons JVM / conteneur / classloader ont des opinions différentes sur les classes qui doivent être chargées à partir du chemin de démarrage par rapport au chemin de classe application / webapp.

Cela est compliqué par le fait que serialver se charge toujours toujours à partir de bootclasspath. Vous devrez donc peut-être utiliser -J-Xbootclasspath comme ci-dessous pour simuler un comportement différent:

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

Une autre approche consiste à utiliser javap, par exemple:

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

J'ai conçu un utilitaire pour cela, basé sur certaines réponses de SO. Voici ma classe.

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

maladroit mais fonctionne

J'utiliserais un outil de reverse engineering
1) décompressez les bocaux
2) lancez, disons, jad sur l’arbre des fichiers de classe
3) exécutez grep ou tout autre outil de recherche sur cette nouvelle arborescence de source pour rechercher la version en série de l'id.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top