2012-08-14 9 views
5

I JPAとHibernateを使用してJSON文字列を自動的にシリアライズおよび逆シリアル化する方法はありますか?

CREATE table "user"; 
ALTER TABLE "user" ADD COLUMN preferences TEXT; 
のコラム「環境設定」を持っているデータクラス/テーブル「ユーザー」を持っているプリファレンスタイプはTEXTであり、私はそこにJSONを格納しています。

public class User extends AbstractEntity{ 
public String preferences; 
} 

のでuser.preferences値Iが

user.preferences.notifyByEmail 

またはデータオブジェクトに

user.preferences.get("notifByEmail"); 
user.preferences.set("notifByEmail",true); 
をラップする必要のないようにアクセスすることができますので、私はいくつかの注釈でそれをラップすることができますどのように "{notifyByEmail:1, favouriteColor:"blue" }"

です

ジャクソンの注釈があると思います私はJPAにかなり新しいです

@JsonGenerate 
public String preferences; 

のようにddは分野に関し、ドキュメントが急峻です。

私のケースはかなり共通していると思います。誰かが例を挙げることはできますか?

+0

このデータをJSON文字列として保存し、別々の別個のフィールド(ここでは、booleanとenumのタイプ)として保存することの根拠は何ですか? – Samuel

+0

理論的には、すべてのキー値の設定を別のフィールドとしてサポートしたくありません。 プリファレンスキー:値が大きくなり、ハングアップしています。かなり多くあります。モデルの変更やそれぞれのデータベースへのフィールドの追加は過度のことです。 – Roman

+0

属性表を使って値を話すことを検討しましたか?ユースケースは実際には一般的ですが、あなたの提案されたソリューションは、リレーショナルモデルにはあま​​り適していません。 – Samuel

答えて

6

正直、私はあなたの最高のソリューションは、あなたのプロパティのために別のテーブル(環境設定)を作成することだと思います。

+------------+ 
| preference | 
+------------+---------+------+-----+ 
| Field  | Type | Null | Key | 
+------------+---------+------+-----+ 
| user_id | bigint | NO | PRI | 
| key  | varchar | NO | PRI | 
| value  | varchar | NO |  | 
+------------+---------+------+-----+ 

あなたはこのようなあなたのエンティティでこれをマップすることができます。

@Entity 
public class User 
{ 
    @Id 
    private Long id; 

    @ElementCollection 
    @MapKeyColumn(name = "key") 
    @Column(name = "value") 
    @CollectionTable(name = "preference", 
     joinColumns = @JoinColumn(name = "user_id")) 
    private Map<String, String> preferences; 
} 

この方法では、データベースがより正規化され、あなたはJSONとして設定を保存するような「創造的な解決策」で浮気する必要はありません。

+0

包括的な説明をいただきありがとうございます。やってみます! – Roman

+7

これは質問がそれを要求した方法ではありません。 –

+2

@HiramChirino私は質問者の代わりに何か間違っているとは思わない。特に、代替案がより良い解決策を提供する可能性がある場合。質問者はこの解決策(有益)に満足しているように見えました。答えは簡単でも間違ってもいないので、投票する理由は何もありません。 Stackoverflowのために[[いつの時点でヘルプページを参照してください](http://stackoverflow.com/help/privileges/vote-down)を参照してください。 – siebz0r

2

あなたは本当に、ほとんどの推奨は次に何をしていることのようなものが必要な場合:

public class User extends AbstractEntity{ 
    @JsonIgnore //This variable is going to be ignored whenever you send data to a client(ie. web browser) 
    private String preferences; 

    @Transient //This property is going to be ignored whenever you send data to the database 
    @JsonProperty("preferences") //Whenever this property is serialized to the client, it is going to be named "perferences" instead "preferencesObj" 
    private Preferences preferencesObj; 

    public String getPreferences() { 
    return new ObjectMapper().writeValueAsString(preferencesObj); 
    } 

    pbulic void setPreferneces(String preferences) { 
    this.preferences = preferences; 
    this.preferncesObj = new ObjectMapper().readValue(preferences, Preferences.class); 
    } 

    pubilc Preferences getPreferencesObj() { 
    return preferencesObj; 
    } 

    public void setPreferencesObj(Preferences preferencesObj) { 
    this.preferencesObj = preferencesObj; 
    } 
} 

追加メモ:

  • たぶん、私有財産「好み」が削除される可能性があり、のみを使用ゲッターとセッター。
  • 私はそのコードをテストしていません。
  • 上記のコードは、Jackson ObjectMapperとHibernateモジュールを使用することを意図しています。
+0

JSON配列の例も提供してください。私はannonionを使用してJSON Arrayをデシリアライズするのに苦労しました。 – Azerue

+0

これは、 'User'が持つことができるすべての異なる設定を必要とする' Preferences'というクラスを必要としませんか? – Christian

+0

はい。動的なものを好むなら、代わりに地図を使うことをお勧めします。 –

6

JPA Converterを使用してこれを達成できます。

エンティティ;

@Id 
@GeneratedValue 
Long id; 

@Column(name = "mapvalue") 
@Convert(converter = MapToStringConverter.class) 
Map<String, String> mapValue; 

コンバータ:

@Converter 
public class MapToStringConverter implements AttributeConverter<Map<String, String>, String> { 

    ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public String convertToDatabaseColumn(Map<String, String> data) { 
     String value = ""; 
     try { 
      value = mapper.writeValueAsString(data); 
     } catch (JsonProcessingException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return value; 
    } 

    @Override 
    public Map<String, String> convertToEntityAttribute(String data) { 
     Map<String, String> mapValue = new HashMap<String, String>(); 
     TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() { 
     }; 
     try { 
      mapValue = mapper.readValue(data, typeRef); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return mapValue; 
    } 

} 

セーブデータ:私はthis articleで説明したように

Map<String, String> mapValue = new HashMap<String, String>(); 
mapValue.put("1", "one"); 
mapValue.put("2", "two"); 
DataEntity entity = new DataEntity(); 
entity.setMapValue(mapValue); 
repo.save(entity); 

値は

{"1":"three","2":"two"} 
0

としてDBに格納されます、それはに非常に簡単ですHibeを使用してJSONオブジェクトを保持するルネーテ。 、詳細情報については

<dependency> 
    <groupId>com.vladmihalcea</groupId> 
    <artifactId>hibernate-types-52</artifactId> 
    <version>${hibernate-types.version}</version> 
</dependency> 

hibernate-types open-source projectをチェックアウト:

あなたは、単に次の依存関係を使用してMavenの中央を経由して にそれらを得ることができ、手動ですべてのこれらのタイプを作成する必要はありません。

@TypeDef(
    name = "jsonb-node", 
    typeClass = JsonNodeBinaryType.class 
) 

とエンティティマッピングは次のようになります。

は今、あなたはどちらかのクラスレベル上またはpackage-info.javaパッケージレベルのdescriptiorで新しい型を宣言する必要があります:

@Type(type = "json-node") 
@Column(columnDefinition = "json") 
private JsonNode preferences; 

これだけです!

関連する問題