私はこの問題に直面してきました.シリアライゼーションのhibernateオブジェクトは、Hibernateからのインストルメント化されたすべてのコードを含む予期しないxmlを生成します.
オブジェクトをシリアル化する前に、オブジェクトのクリーニングを行いました。
しかし、オブジェクトを直接シリアル化するための標準オプションはありますか?
XStreamは、Hibernateコレクションを処理するための個別のモジュール/jarを提供するようになりました。例については、XStreamのFAQを参照してください。
以前に XStream を使用したことはありませんが、Hibernate 管理のエンティティをシリアル化しました。面白くない。
2 つの大きな問題があります。
前者は明らかです。シリアル化するには実際のデータが必要です。後者はそうではありません。コレクション インターフェイスに対して宣言する 1 対多の関係 (例: Set<T>
) は、Hibernate 独自の (シリアル化できない!) コレクション実装によってプラグインされます。これは、Hibernate のクラスがオブジェクトに影響を与えている可能性があります。
私はこれを行うリフレクションコード(実際には内省的)を書くことになりました:
ステップ 2 が重要であることに注意してください。セッションを閉じる前にコレクションを置き換えると、Hibernate は閉じた直後に独自のコレクションを元に戻します...
編集: @cliff.meyers は、私が言及するのを忘れていた実装の詳細を発見しました: これを行う場合、オブジェクト グラフの移動を自分のエンティティのみに制限し、循環参照パスを監視する必要があります (例: オブジェクトへの参照をキャッシュすることにより、すでに歩いています)。
私はある程度十分な解決策を思いつきました。私のアプリケーションでは、PersistentSet だけが XStream によって生成された XML を混乱させていました。そのため、別の Converter to XStream (開いている Hibernate Session とライブ オブジェクトで実行される) を追加しました。
XStream xs = new XStream();
xs.registerConverter(new CollectionConverter(xs.getMapper()) {
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
org.hibernate.collection.PersistentSet ps = (PersistentSet) source;
super.marshal(new HashSet(ps), writer, context);
}
@Override
public boolean canConvert(Class type) {
return type.isAssignableFrom(org.hibernate.collection.PersistentSet.class);
}
}, XStream.PRIORITY_VERY_HIGH);
String s = xs.toXML(processInstance);
シリアライズされた XML は次のようになります。
<processLogs class="org.hibernate.collection.PersistentSet">
<pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>
<id>813017</id>
<entryDate>
<time>1310832421216</time>
<timezone>GMT</timezone>
</entryDate>
<eventI18NKey>process.log.action-performed</eventI18NKey>
<additionalInfo>Wydrukuj wniosek</additionalInfo>
<logValue>GENERATE_APPLICATION</logValue>
<logType>PERFORM_ACTION</logType>
<state reference="../../../definition/states/pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration[8]"/>
<processInstance reference="../../.."/>
<user reference="../../../creator"/>
</pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>
<pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>
<id>808211</id>
<entryDate>
<time>1310828206169</time>
<timezone>GMT</timezone>
</entryDate>
<eventI18NKey>process.log.action-performed</eventI18NKey>
<additionalInfo>Zaakceptuj</additionalInfo>
<logValue>ACCEPT</logValue>
<logType>PERFORM_ACTION</logType>
<state reference="../../../definition/states/pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration[4]"/>
<processInstance reference="../../.."/>
<user reference="../../../creator"/>
</pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>
私の場合、class 属性は重要ではなかったので、その値を無視しました。もちろん、いじることができます。
Codehaus JIRA には、これ (およびサンプル コード) に関する情報がいくつかあります。
http://jira.codehaus.org/browse/XSTR-226
他のリモート処理の実装 (Axis 1、Blaze DS など) 向けに、この種の問題を回避するためのツールをいくつか作成しました。私たちが行ったことは、Dan のソリューションと非常に似ていますが、多くの場合、すべてのデータに関心があるわけではないため、どのオブジェクト パスをたどり、どのオブジェクト パスを「切り取る」かを宣言する機能を追加しました。また、「n + 1 選択」の問題が何千回も発生するという深刻な問題が発生する可能性があります。:) オブジェクト グラフを 1 回だけ処理する必要があるため、XStream コンバーターを実装するのが最適な方法だと思います。セッションに FlushMode.MANUAL を設定すると、Hibernate が厄介なことをすることなく、オブジェクト グラフを変更できるはずです。ただし、これはやや高度な手法であるため、注意して使用してください。
休止状態を使用していませんが、同様の問題に直面しました。私はエニティプルーナーを見ましたが、より単純な解決策を探していたので、探していたものとはまったく異なりました。
リフレクションを使用して、CGLIB 拡張オブジェクトをチャームのようにデプロキシする非常に単純なソリューションを思いつきました。
例とコードについては、 http ://www.anzaan.com/2010/06/serializing-cglib-enhanced-proxy-into-json-using-xstream/にアクセスしてください。
使用していませんが、xstream-for-beansが適しているようです (引用):
このプロジェクトは、次の側面で XStream を強化するマッパーとコンバーターの実装を提供します。
- ゲッターとセッターによって公開されたオブジェクトをシリアライズします。フィールドで使用できる XStream 機能は、getter/setter プロパティ用に定義されたプロパティで機能します。
- 管理対象オブジェクトのシリアル化をサニタイズ: 無関係なフィールドとクラス情報を自動的に省略します。
- 「オフライン」フィールドとプロキシ オブジェクトを処理します。
Converter
残念ながら、クローズドソースプロジェクトの一部として、この問題に対処するためにカスタム XStream を書いたことがあります。xstream-for-beans はまったく同じ問題を扱っており、試してみる価値があります。
過去にTerracotta のPojoizerユーティリティを使用して成功しましたが、もう維持されていないと思います。