您好我们正在生成桌面应用程序。在我们的项目中,我们需要使用javax.swing.ImageIcon
,如果是服务器请求,我们需要发送此对象。
这里的问题是,如果我们在两个环境中使用相同的JRE,它的工作正常,如果没有,我们得到java.io.InvalidClassException: javax.swing.ImageIcon; local class incompatible: stream classdesc serialVersionUID = -962022720109015502, local class serialVersionUID = 532615968316031794
是否有任何解决方案可以避免这种情况,任何建议都表示赞赏。提前致谢
对于我所做的是,我只是获得了ImageIcon.java文件并使用我自己的包删除了包。在这里我硬编码了serialversionuid,这是推荐的吗?
答案 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);
}
}
}