JPAのバージョンは2.1と前バージョンから0.1しか上がっていないが、非常にいいものが追加されている。
2.1の目玉機能としてはストアド呼び出しが可能になったとかあるのだろうが、基本ストアド使いたくないのでおいらは無視する。
で、地味・・・ではなくド派手なのにあまり語られない新機能もある。
それがコンバータだ。やっときた!
これはどういうものかというと、たとえば、DB上には文字列で保存をして、Entity上はIntegerで保持するといったもの。
もちろん、ラッパクラス以外でもふつうに使えるので、アプリケーションに合わせて積極的にコンバータを作っておくと既存のDBを変更せず、かといってそれにEntity操作が引きずられない、非常に良いものが出来上がる。
コードは昨日のエントリのJPA2.0のサンプルをもとに変更してみよう。
addressという文字列型には都道府県が入っていたので、そこに使ってみる。
これをDB上は文字列のまま変更せず、Entity上で扱う場合はIntegerで都道府県コードを利用するようにしてみよう。
コンバータ作成
@Converter public class AddressConverter implements AttributeConverter<Integer, String>{ @Override public String convertToDatabaseColumn(Integer x) { if(x == null){ return ""; } switch(x){ case 1:return "北海道"; case 2:return "青森県"; case 3:return "岩手県"; case 4:return "宮城県"; case 5:return "秋田県"; case 6:return "山形県"; case 7:return "福島県"; default:return "あとはめんどくせ"; } } @Override public Integer convertToEntityAttribute(String y) { if(y == null){ return null; } switch(y){ case "北海道":return 1; case "青森県":return 2; case "岩手県":return 3; case "宮城県":return 4; case "秋田県":return 5; case "山形県":return 6; case "福島県":return 7; default:return -1; } } }
Entityにコンバータを設定する
@Entity @Access(AccessType.FIELD) public class Customer implements Serializable { private static final long serialVersionUID = 1L; @Id @Basic(optional = false) public Long id; public String name; @Convert(converter = AddressConverter.class) public Integer address; }
「@Convert」がそれ。これでコンバータのクラスを設定する。
グローバル設定
グローバルに設定した場合はコンバータの指定はいらなくなる。設定方法は簡単。
@Converter(autoApply = true)
これだけでその型が見つかると自動でコンバータが適用される。
そのため、上記のサンプルのようなIntegerとかラッパクラスでは利用してはいけない。
Integerを使っているところすべてに適用されてしまうからだ。
コンバータのすごさがおわかりだろうか。これでオブジェクト指向らしいコードが標準APIのみで書ける。
コレクション的なものを安全にカンマ区切りで文字列として突っ込む、取り出すとかも可能だ。
JavaSEで動かす場合、コンバータのクラスがJPAに自動登録されないためEntityと同じくpersistence.xmlまたはorm.xmlに記述するとよいだろう。