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

Javadoc のjavax.swing.ImageIcon内容:

警告: このクラスのシリアル化されたオブジェクトは、将来の Swing リリースと互換性がありません。現在のシリアライゼーション サポートは、同じバージョンの Swing を実行しているアプリケーション間の短期間の保存または RMI に適しています。1.4 の時点で、すべての JavaBeansTM の長期保存のサポートが java.beans パッケージに追加されました。java.beans.XMLEncoder を参照してください。

そこで提案されているように、シリアル化する代わりにjava.beans.XMLEncoder(and )を使用してみてください。java.beans.XMLDecoder

于 2013-09-13T10:45:36.677 に答える
0

serialVersionUID フィールドを置き換えることにより、1.6.0_26 未満の Java バージョンでシリアライズされた ImageIcon クラスを使用し、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 に答える