読者です 読者をやめる 読者になる 読者になる

JPAのConverterで独自クラスを扱う

Java DB JPA

ConverterをOpenJPAで使おうとしましたが,今のOpenJPAのリリースではConverterに対応していませんでした.

ConverterはJPA2.1以降の実装にしか対応していません.HibernateかEclipseLinkでやりましょう.
私はEclipselinkです



さてコンバーターの説明はこちらでご覧ください.
JavaEE 7 JPA 2.1の新機能コンバータ - しんさんの出張所 はてな編
JPA2.1 の Converter を enum + コードファーストで試す - hd 4.0

上記2記事にあるように,JPAでDBに入っているデータと実際にJava上で扱いたいデータ型が異なるときにコンバーターは非常に便利です.

public Hoge{
    private Integer fuga;
    private Integer piyo;
    // setter, getter省略
    public Hoge(String dododo) {
        if(dododo.length != 2) throw new IllegalArgumentExeption();
        this.fuga = //省略
    }
    @Override
    public String toString() {
        return this.fuga.toString() + this.piyo.toString();
    }
}
@Converter
public HogeConverter implements AttributeConverter<Hoge, String>{
    @Override
    public String convertToDatabaseAttribute(Hoge hoge) {
        return hoge.toString();
    }
    @Override
    public Hoge convertToEntityAttribute(String value) {
        return new Hoge(value);
    }
}

例えばこんなのを作ってあとはエンティティクラスのご所望のフィールドに@Convert(converter = "name")とするだけで,出し入れの時にConverterを適用してくれるのです.

ところが

Entityクラスのインスタンスに対して

getHoge().setPiyo(2);

とかした後にEntityManager#persistをしてみても,どうもうまくいきません.
newしたオブジェクトだったらpersistすると更新されるようですが,インスタンスの中身を書き換えただけではJPAには変更されたと認識されないようです.

いろいろ調べた結果
Entityクラスの定義で

@Basic
@Mutable // <- 重要
private Hoge hoge;  

としなければならなかったようです.
@Mutable | EclipseLink 2.4.x Java Persistence API (JPA) Extensions Reference

毎回インスタンスを生成する必要があるものについてはそんなに気にしなくていいのですが,中身が書き換わるMutableな独自クラスを定義する場合はご注意ください.

それにしてもJPAは日本語ドキュメントが少なくて大変だ.