2011-05-22 55 views
1

我正在使用使用JBPM 3.1和MySQL的應用程序。核心問題是,流程實例的變量包含外部非JBPM Serializable類的舊版本。當主應用程序升級時,由於特定類實例的SUID已在主應用程序中更改,因此這些流程實例會導致JBPM拋出異常。通過MySQL直接重新序列化JBPM過程變量

我相信我有使用以下描述的技術固定反序列化過程的方法:

How to deserialize an object persisted in a db now when the object has different serialVersionUID

不過,我的問題是搞清楚在MySQL JBPM商店流程實例變量,所以我可以編寫一個可以對所有實例的所有變量進行交互的程序,對變量重新進行串行化處理,以便有問題的類將擁有新的SUID,因此JBPM可以針對進程進行操作。

我最初看JBPM表時,看起來JBPM_BYTEARRAY和/或JBPM_BYTEBLOCK可能是要操作的表。但是,我不確定如何繼續。我猜每個流程變量都存儲在一個包裝容器類中。那班是org.jbpm.context.exe.VariableInstance?或者是別的什麼?

我想,如果我在類路徑中有正確的jar文件,並且我知道JBPM用於在MySQL中存儲過程變量的主類實例,我可以反序列化類(它將修復SUID問題嵌入式問題類實例),並將該類重新串行化。由於JBPM文檔確實提到了有關轉換器的內容,我不確定是否必須複製JPBM在反序列化時執行的轉換過程,或者標準java反序列化是否足夠。

回答

1

JBPM的一些分析表明二進制數據可能會跨多個記錄拆分。這可能不是mysql本身的情況,但JPBM代碼被編寫爲支持多個RDBM,並且一些對二進制記錄的大小有限制。

由於這個問題使我獲得了風滾草的獎勵,所以我不會在必須滿足的最後期限內獲得可用的基於mysql的答案,所以我重新考慮了問題發生的核心問題和操作環境,並提出了一個避免執行直接mysql操作所需的解決方案。

有問題的主要應用程序已經對JBPM進行了一些自定義修改,所以我實現的解決方案改變了JBPM源代碼,它執行流程實例變量的反序列化。這避免了處理從RDBM中提取反序列化二進制數據的JBPM邏輯的需要。

在類org.jbpm.context.exe.converter.SerializableToByteArrayConverter中,我修改了代碼以使用返回類的最新SUID的自定義ObjectInputStream類。如果新類包含新字段,則僅使用問題中引用的帖子中描述的最新版本的類替換描述符的技術不起作用。這樣做會導致數據結束異常,因爲基本反序列化代碼嘗試訪問舊的反序列化版本的「新」字段。

因此,我只需要替換SUID,但保留描述符的所有其他部分相同。由於JDK不會使ObjectStreamClass可擴展,因此我創建了ObjectInputStream的子類,該子類基於給定的調用模式返回新的SUID,這是java庫在對數據進行反序列化時針對ObjectInputStream執行的。

模式:讀取反序列化對象的標頭時,會調用readUTF()函數(以獲取類名稱),然後調用readLong()。因此,如果這個調用序列發生,並且如果readUTF()返回類名稱,我想要更改SUID,我將返回readLong()調用中較新的SUID。

自定義代碼將讀取一個配置文件,該文件指定應映射到列出的類的最新SUID的類名和關聯的SUID。這允許在將來不用修改自定義代碼時映射替代類。

注意,這種方法適用於一般的反序列化操作,其中需要將舊的SUID映射到指定類的最新SUID,並且只保留序列化類描述符的其他部分以避免數據結束的問題較新的類定義包括在較舊的類定義中不存在的其他字段聲明。

+0

我感覺你的痛苦是:風滾草徽章..嘿 – mcraen 2015-02-02 20:34:41

0

您是否知道您是否做出了違反合同的更改,或者僅僅是簡單地添加新字段?如果只是簡單地添加新字段,那麼只需定義之前的serialversionuid即可。否則,您必須閱讀所有具有不同serialversionid的變量,並將它們保存在新類中,因爲您是唯一知道如何轉換它們的人。

+0

這應該是一個評論,但我不能只設置SUID,因爲他們是具有序列化類的新版本的客戶,所以如果SUID設置爲較舊的值,那麼這些客戶就會遇到反序列化問題。 – ewh 2011-06-01 04:23:33

+0

我不明白你的答案是如何處理舊的序列化對象的。 – 2011-06-01 16:26:12

+0

當readLong()被JRE庫調用時,我返回當前類的SUID long值而不是序列化數據中的SUID值。這樣SUID檢查就會通過。當然,正如我注意到的,我的readLong()實現應該只在給定的調用模式發生在我的ObjectInputStream實現(這只是基本實現的監視包裝)時執行此操作。 – ewh 2011-06-03 03:15:03