JPAとJacksonで。

そこそこはまったこと。

JPAでエンティティ作ってそのまんまjsonやxmlにする。

いろいろ試行錯誤して結構形になってきました。ホントに試行錯誤したよ。。。。

で、一から環境作るところはあまりに試行錯誤しすぎて記憶も朧なので割愛。最近ハマったことです。

環境は

  • mariaDB
  • Glassfish4.0
  • OpenJPA2.0

jsonプロバイダにはGlassfishのJersey +Jacksonを使います。

余談ですが最初はTomcat7を使うつもりでOpenJPAのバグを踏んで諦めました。(←試行錯誤)

なんとかDBからエンティティを作ってjsonにしようとするところまで行きついたのですが、以下エラーが返ることに。


StandardWrapperValve[Jersey REST Service]: Servlet.service() for servlet Jersey REST Service threw exception
java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.String

なんかものすごい初歩的なExceptionなんだけど、対処方法探すのに結構かかりました。

ようはjsonって中身、文字列だよね?数字はダメだよってことなんですが、DBからエンティティ生成してるので型を変えるのは厳しい。

Integerならいけるけどそれじゃ桁数ががががが。

jsonエンジンは引き受けた値を文字列にしてjsonにして返すのがお仕事なわけで、当然日付や数値を文字列に変換する機能はある。ただし、castできる型じゃないとダメってこと。

勿論日付もUNIXタイムの数値が文字列で返ってきます。

これを必要な形式の文字列にして返すには自力でシリアライズする必要があるとのこと。

JacksonのJsonSerializerクラスを継承し、serializeメソッドをオーバーライドします。

  • 数値
package test.json;
import java.io.IOException;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

public class NumericSerializer extends JsonSerializer<Object> {
 @Override
 public void serialize(Object value, JsonGenerator gen,
 SerializerProvider provider) throws IOException,
 JsonProcessingException {

String formatNumber = value.toString();
 gen.writeString(formatNumber);

}

}

  • 日付
package test.json;
import java.io.IOException;
import java.text.SimpleDateFormat;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

public class DateSerializer extends JsonSerializer<Object> {
 @Override
 public void serialize(Object value, JsonGenerator gen,
 SerializerProvider provider) throws IOException,
 JsonProcessingException {

SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
 String formatDate = df.format(value);
 gen.writeString(formatDate);

}
}

作成したSerializeクラスを@JsonSerializeアノテーションを利用してEntityクラスのメンバへ設定。

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="User")
@Entity
public class User implements Serializable {
 private static final long serialVersionUID = 1L;

@Temporal(TemporalType.DATE)
 @JsonSerialize(using = DateSerializer.class)
 @XmlElement(name="InputDate",required=true)
 private Date InputDate;

private byte IsValid;

@Temporal(TemporalType.DATE)
 @JsonSerialize(using = DateSerializer.class)
 @XmlElement(name="UpdateDate",required=true)
 private Date UpdateDate;

@XmlElement(name = "UserNameFirst", required = true)
 private String UserNameFirst;

@XmlElement(name = "UserNameLast", required = true)
 private String UserNameLast;

@Id
 @XmlElement(name = "UserID", required = true)
 @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
 @JsonSerialize(using = NumericSerializer.class)
 @XmlSchemaType(name = "ID")
 private BigInteger UserID;
}

次に悩んでるのは外部キーがある時のStackOverflowError

それはまた次回に・・・・。

書けそうならTomcat7でOpenJPAを諦めた理由あたりも書こうかな。

広告
カテゴリー: お仕事, プログラミング タグ: , パーマリンク

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中