2

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

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

4

3 回答 3

4

Javadocjavax.swing.ImageIcon包含:

警告:此类的序列化对象将与未来的 Swing 版本不兼容。当前的序列化支持适用于运行相同版本 Swing 的应用程序之间的短期存储或 RMI。从 1.4 开始,java.beans 包中添加了对所有 JavaBeansTM 长期存储的支持。请参阅 java.beans.XMLEncoder。

正如那里所建议的那样,您应该尝试使用java.beans.XMLEncoder(and java.beans.XMLDecoder) 而不是序列化。

于 2013-09-13T10:45:36.677 回答
3

类不兼容。解决方案是在两侧使用相同的 JRE,或者不使用 serialized ImageIcon

于 2013-09-13T09:03:39.633 回答
0

有一个解决方案可以使用 java 版本低于 1.6.0_26 的序列化 ImageIcon 类,并通过替换 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);
        }
    }
}
于 2016-12-14T16:08:50.073 回答