1

JBPM 3.1 と MySQL を使用するアプリケーションを使用しています。中心的な問題は、JBPM 以外の外部Serializableクラスの古いバージョンを含む変数を持つプロセス インスタンスがあることです。メイン アプリケーションがアップグレードされると、特定のクラス インスタンスの SUID がメイン アプリケーションで変更されたため、これらのプロセス インスタンスによって JBPM によって例外がスローされます。

以下で説明する手法を使用して、逆シリアル化プロセスを修正する方法があると思います。

オブジェクトのserialVersionUIDが異なる場合に、データベースに永続化されたオブジェクトをデシリアライズする方法

ただし、私の問題は、MySQL JBPM がプロセスインスタンス変数を格納する場所を特定することです。そのため、すべてのインスタンスのすべての変数を対話処理し、変数を再シリアル化して、問題のあるクラスが新しい SUID を持つようにするプログラムを作成できるため、JBPM はプロセスに対して操作します。

JBPM テーブルを最初に見たところ、JBPM_BYTEARRAY および/または JBPM_BYTEBLOCK が操作対象のテーブルである可能性があるようです。ただし、どのように進めればよいかわかりません。各プロセス変数はラッピング コンテナー クラスに格納されていると思います。そのクラスorg.jbpm.context.exe.VariableInstanceですか?それとも別のものですか?

クラスパスに適切なjarファイルがあり、JBPMがプロセス変数をMySQLに格納するために使用するメインクラスインスタンスが何であるかを知っている場合、クラスをデシリアライズできます(これにより、埋め込まれた問題クラスのSUIDの問題が修正されます)インスタンス)、クラスを再シリアル化します。JBPM のドキュメントにはコンバーターに関する記述があるため、デシリアライズ時に JPBM が行う変換プロセスを再現する必要があるのか​​、それとも標準の Java デシリアライズで十分なのかはわかりません。

4

2 に答える 2

1

JBPM の一部の分析では、バイナリ データが複数のレコードに分割されている可能性があることが示されています。これは mysql 自体には当てはまらないかもしれませんが、JPBM コードは複数の RDBM をサポートするように書かれており、バイナリ レコードのサイズに制限があるものもあります。

質問は私にタンブルウィードの報酬をもたらしたので、私が守らなければならなかった期限内に使用可能なmysqlベースの回答を得ることはできなかったので、コアの問題と問題が発生する操作コンテキストを再考し、思いついた.直接mysql操作を実行する必要を回避したソリューション。

問題のメイン アプリケーションには、JBPM へのカスタマイズ変更が既にいくつか含まれているため、実装したソリューションでは、プロセス インスタンス変数の逆シリアル化を実行する変更された JBPM ソースを実装しました。これにより、RDBM からデシリアライズされたバイナリ データを抽出する JBPM ロジックを処理する必要がなくなります。

classorg.jbpm.context.exe.converter.SerializableToByteArrayConverterで、クラスの最新の SUID を返すカスタムObjectInputStreamクラスを使用するようにコードを変更しました。新しいクラスに新しいフィールドが含まれている場合、質問で参照されている投稿で説明されているように、記述子をクラスの最新バージョンに置き換えるだけの手法は機能しません。これを行うと、データの終わりの例外が発生します。これは、基本の逆シリアル化コードが、クラスの古い逆シリアル化バージョンの「新しい」フィールドにアクセスしようとするためです。

したがって、SUID を置き換えるだけで済みますが、記述子の他のすべての部分はそのままにしておきます。JDK は拡張可能ではないため、データを逆シリアル化するときにJava ライブラリが実行する特定の呼び出しパターンに基づいて、新しい SUID を返す のObjectStreamClassサブクラスを作成しました。ObjectInputStreamObjectInputStream

パターン: 逆シリアル化されたオブジェクトのヘッダーを読み取るとき、readUTF()(クラス名を取得するために) 関数が呼び出され、その後にreadLong()呼び出しが続きます。したがって、この呼び出しシーケンスが発生しreadUTF()、SUID を変更したいクラス名が返された場合、readLong()呼び出しで新しい SUID を返します。

カスタム コードは、リストされているクラスの最新の SUID にマップする必要があるクラス名と関連する SUID を指定する構成ファイルを読み取ります。これにより、カスタム コードを変更することなく、将来的に代替クラスをマッピングできます。

このアプローチは、古い SUID を指定されたクラスの最新の SUID にマップする必要がある一般的な逆シリアル化操作に適用できることに注意してください。また、シリアル化されたクラス記述子の他の部分をそのままにして、新しいクラス定義が新しいクラス定義の場合にデータの終わりの問題を回避します。古いクラス定義には存在しない追加のフィールド宣言が含まれています。

于 2011-06-01T04:57:56.237 に答える
0

契約を破る変更を加えたのか、それとも単に新しいフィールドを追加しただけなのか知っていますか? 新しいフィールドを追加するだけの場合は、以前の serialversionuid を定義するだけです。それ以外の場合は、異なる serialversionid を持つすべての変数を読み取り、新しいクラスに保存する必要があります。それらを変換する方法を知っているのはあなただけだからです。

于 2011-05-31T18:36:19.620 に答える