SpringでNeo4jを利用する際の注意点

spring-bootからNeo4jを利用する場合、spring-data-neo4j(neo4j-ogm)と言ったライブラリでアクセスする事になります。
その際、バグと思われる現象に遭遇しましたので、忘れないように記しておきます。

概要

ValueObjectの配列またはリストをフィールドにもつEntityを作成します。
Neo4jにValueObjectをNodeとして登録させたくない為、フィールドをコンバータで文字列シリアライズしSaveを行いました。
Saveは正常に行われ、Neo4jへのストアされた内容も想定通りのものでしたが、このエンティティをLoadすると、コンバータの処理で型キャストエラーが発生しLoadに失敗します。

詳細

  • LoadできるEntity
    下記のEntityはSave、Loadが行えます

 

  • LoadできないEntity
    下記のEntityはSaveできるが、Load時にエラーが発生する

ValueObjectのListフィールドを追加する。フィールドをコンバーターにより文字列(Json)に変換する

このエンティティをSave後にLoadを実行すると、下記のような例外が発生し失敗します。スタックトレースから、キャストエラーが確認できます。

ここで発生している例外がListからStringへの変換例外だった為、なぜ発生するのか原因がわかりませんでした。Load時に行う処理は文字列(JSON)からValueObjectへの変換のはずです。なぜListを文字列にCastしようとしているのか、、、

原因

スタックトレースを追っていくと、GraphEntityMapperクラスに問題がありそうです。
当該箇所を確認してみます。

配列、Listの場合の分岐があります。どうやら、デシリアライズ先のフィールドがList(配列)の場合のみここで型の変換を行っています。

Neo4jのNodeは、プロパティに数値、文字列、真偽値またはそれらの配列を持つ事ができます。そのため為のロジックだと思いますが、コンバータの有無を確認せずに型変換を行っています。Writerの中でCallされるコンバータは文字列を期待ていますがListが渡される為、文字列にキャストを行おうとし例外となりました。

対応

色々試行錯誤した結果、当該部分を削除する対応を取りました。
テストして見る限り、動作に変わりは無いようなのですが、

まとめ

spring-data-neo4jでList(配列)フィールドにコンバーターを設定する場合は、本現象が発生します。
また、本現象ですが、キャッシュオブジェクトが利用されると再現しませんのでご注意ください。凄くハマりました(–;