反序列化二进制类文件的内容时ClassNotFoundException

时间:2011-06-09 22:31:10

标签: java class file loader deserialization

我对Java知之甚少。我正在尝试读取一个包含int的文件和一个名为“Automobile”的类的各种实例。但是,当我反序列化它时,程序抛出一个ClassNotFoundException,我似乎无法理解为什么。

以下是代码:

        try {
        FileInputStream fin = new FileInputStream(inputFile);
        ObjectInputStream input = new ObjectInputStream(fin);

        conto = input.readInt();

        Automobile[] macchine = new Automobile[conto];

        for(int i = 0; i < conto; i++) {
            macchine[i] = (Automobile)input.readObject();
        }

        String targa;
        System.out.print("\nInserire le cifre di una targa per rintracciare l'automobile: ");
        targa = sc1.nextLine();

        for(int i = 0; i < conto; i++) {
            if(macchine[i].getTarga().equals(targa))
                System.out.println(macchine[i]);
        }

    } catch(IOException e) {
        System.out.println("Errore nella lettura del file "+inputFile);
    } catch(java.lang.ClassNotFoundException e) {
        System.out.println("Class not found");
    }

提前致谢。

编辑:这是stacktrace

java.lang.ClassNotFoundException: es4.Automobile
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:604)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1575)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    at es4p2.Main.main(Main.java:35)

7 个答案:

答案 0 :(得分:9)

反序列化序列化对象树时,所有对象的类必须位于类路径中。在这种情况下,ClassNotFoundException最有可能意味着所需的类之一不在类路径上。您必须解决此问题才能使反序列化工作。

在这种情况下,es4.Automobile缺失。


  

问题是由我所做的自定义异常引起的吗?

我能想到的唯一其他可能性是:

  • es4.Automobile对其他缺少的类
  • 有直接或间接依赖关系
  • es4.Automobile或依赖类的静态初始化抛出了一个未在类内部捕获的异常。

但是这些都应该(我认为)导致了不同的堆栈跟踪。


  

我刚注意到包名是es4p2,而不是es4。为什么说es4?可能是因为保存文件的程序使用另一个包名吗?

我不知道他们为什么会有所不同。您需要与编写代码/生成序列化对象的人交谈。但是,这很可能是 问题的原因。具有不同包名称的类是不同的类。周期。


当捕获到意外异常时,您应始终输出(或更好地,记录)堆栈跟踪。这将告诉你(和我们)更多关于出错的地方,在这种情况下,缺少类的名称。

答案 1 :(得分:1)

如果您的类Automobile不在运行时类路径中,则通常会发生这种情况。

答案 2 :(得分:1)

这是老问题,但这可能对其他人有所帮助。我遇到了同样的问题,问题是我没有使用当前的线程类加载器。您将在下面找到我在grails项目中使用的序列化程序类,应该非常简单地在java中使用它 希望这有帮助

public final class Serializer<T> {

/**
 * Converts an Object to a byte array.
 *
 * @param object, the Object to serialize.
 * @return, the byte array that stores the serialized object.
 */

public static byte[] serialize(T object) {

    ByteArrayOutputStream bos = new ByteArrayOutputStream()
    ObjectOutput out = null
    try {
        out = new ObjectOutputStream(bos)
        out.writeObject(object)

        byte[] byteArray = bos.toByteArray()
        return byteArray

    } catch (IOException e) {
        e.printStackTrace()
        return null

    } finally {
        try {
            if (out != null)
                out.close()
        } catch (IOException ex) {
            ex.printStackTrace()
            return null
        }
        try {
            bos.close()
        } catch (IOException ex) {
            ex.printStackTrace()
            return null
        }
    }

}

/**
 * Converts a byte array to an Object.
 *
 * @param byteArray, a byte array that represents a serialized Object.
 * @return, an instance of the Object class.
 */
public static Object deserialize(byte[] byteArray) {
    ByteArrayInputStream bis = new ByteArrayInputStream(byteArray)
    ObjectInput input = null
    try {
        input = new ObjectInputStream(bis){
            @Override protected Class<?> resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                ClassLoader cl = Thread.currentThread().getContextClassLoader();
                if (cl == null)  return super.resolveClass(desc);
                return Class.forName(desc.getName(), false, cl);
            }
        };
        Object o = input.readObject()
        return o

    } catch (ClassNotFoundException | IOException e) {
        e.printStackTrace()
        return null
    } finally {
        try {
            bis.close()
        } catch (IOException ex) {
        }
        try {
            if (input != null)
                input.close()
        } catch (IOException ex) {
            ex.printStackTrace()
            return null
        }
    }
}

答案 3 :(得分:0)

您的Automobile班级是否有这样的字段?

private static final long serialVersionUID = 140605814607823206L; // some unique number

如果没有,请定义一个。如果有问题,请告诉我们。

答案 4 :(得分:0)

我以比其他答案更简单的方式修复它 - 在多个项目中使用该类时出现问题。

如果您有多个项目,请确保您要反序列化的特定类位于完全相同的路径中!这意味着,该项目内的相同包名等。否则它将找不到它并导致ClassNotFoundException被抛出。

所以,如果它在

  

/myPackage/otherPackage/Test.java

然后确保该路径在您的其他项目中完全相同。

答案 5 :(得分:0)

我有一个类似的问题,一个ObjectInputStream读取序列化的对象。我在运行时使用URLClassloader添加的那些对象的类。问题是ObjectInputStream没有使用我用

设置的Thread ClassLoader
Thread.currentThread().setContextClassLoader(cl);

,而是AppClassLoader,你不能用java 9自定义。所以我把我自己的ObjectInputStream作为原始的一个子类型并覆盖了resolveClass方法:

@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
    String name = desc.getName();
    try {
        return Class.forName(name, false, Thread.currentThread()
                .getContextClassLoader());
    } catch (ClassNotFoundException ex) {
        Class<?> cl = primClasses.get(name);
        if (cl != null) {
            return cl;
        } else {
            throw ex;
        }
    }
}

答案 6 :(得分:-1)

你可以从ClassNotFound异常的消息中访问类名 - 在代码中依赖于它是可怕的 - 但它应该给你一些想法。我希望有一些更好的方法来获取有关序列化对象的信息,而无需使用该类。