面对serialversionuid的问题

时间:2013-09-13 09:00:20

标签: java swing

您好我们正在生成桌面应用程序。在我们的项目中,我们需要使用javax.swing.ImageIcon,如果是服务器请求,我们需要发送此对象。 这里的问题是,如果我们在两个环境中使用相同的JRE,它的工作正常,如果没有,我们得到java.io.InvalidClassException: javax.swing.ImageIcon; local class incompatible: stream classdesc serialVersionUID = -962022720109015502, local class serialVersionUID = 532615968316031794是否有任何解决方案可以避免这种情况,任何建议都表示赞赏。提前致谢

  

对于我所做的是,我只是获得了ImageIcon.java文件并使用我自己的包删除了包。在这里我硬编码了serialversionuid,这是推荐的吗?

3 个答案:

答案 0 :(得分:4)

javax.swing.ImageIcon的Javadoc包含:

  

警告:此类的序列化对象与之不兼容   未来的Swing发布。目前的序列化支持是   适用于运行的应用程序之间的短期存储或RMI   相同版本的Swing。截至1.4,支持长期存储   所有JavaBeansTM都已添加到java.beans包中。请参阅   java.beans.XMLEncoder中。

根据建议,您应该尝试使用java.beans.XMLEncoder(和java.beans.XMLDecoder)而不是序列化。

答案 1 :(得分:3)

这些类不兼容。解决方案是在两侧使用相同的JRE,或者不使用序列化的ImageIcon

答案 2 :(得分:0)

有一个解决方案可以使用序列化的ImageIcon类,其java版本低于1.6.0_26,并通过替换serialVersionUID字段,使用1.6.0_26版本的java版本进行反序列化:

/**
 * Replace serialVersionUID of class {@link javax.swing.ImageIcon}.
 *
 * Hack due to serialVersionUID change but data has not changed since java 1.6.0_26. Cf. http://stackoverflow.com/questions/18782275/facing-issue-with-serialversionuid
 *
 * @return the bytes array converted; or null if conversion failed, or no conversion has been done.
 */
private byte[] convertSerializedData(final byte[] viewsData) {
    try (final ByteSequence byteSequence = new ByteSequence(viewsData)) {
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        final DataOutputStream dataOutputStream = new DataOutputStream(baos);
        while (byteSequence.available() > 0) {
            final byte readByte = byteSequence.readByte();
            dataOutputStream.writeByte(readByte);
            if (readByte == ObjectStreamConstants.TC_CLASSDESC) {
                byteSequence.mark(byteSequence.getIndex());
                boolean discard = false;
                try {
                    final String className = byteSequence.readUTF();
                    long serialVersionUID = byteSequence.readLong();
                    if ("javax.swing.ImageIcon".equals(className) && serialVersionUID == 532615968316031794L) {
                        // Replace serialVersionUID of class javax.swing.ImageIcon
                        serialVersionUID = -962022720109015502L;
                        dataOutputStream.writeUTF(className);
                        dataOutputStream.writeLong(serialVersionUID);
                    } else
                        discard = true;
                } catch (final Exception e) {
                    // Failed to read class name, discard this read
                    discard = true;
                }
                if (discard)
                    byteSequence.reset();
            }
        }
        dataOutputStream.flush();
        return baos.toByteArray();
    } catch (final Exception e) {
        // Conversion failed
    }
    return null;
}

以下是使用此方法的示例,只有在抛出异常时才会调用此方法:

public void restoreViews(final byte[] viewsData) {
    try {
        if (viewsData != null) {
            final ByteArrayInputStream bais = new ByteArrayInputStream(viewsData);
            final ObjectInputStream objectInputStream = new ObjectInputStream(bais);
            readInputStream(objectInputStream);
            objectInputStream.close();
        }
    } catch (final Exception e) {
        try {
            final byte[] viewsDataConverted = convertSerializedData(viewsData);
            if (viewsDataConverted != null) {
                final ByteArrayInputStream bais = new ByteArrayInputStream(viewsDataConverted);
                final ObjectInputStream objectInputStream = new ObjectInputStream(bais);
                readInputStream(objectInputStream);
                objectInputStream.close();
            }
        } catch (final Exception e2) {
            InfonodeViewManager.LOGGER.error("Unable to restore views", e);
        }
    }
}