きり丸の技術日記

技術・エンジニアのイベント・資格等はこちらにまとめる予定です

【Java】簡単にディープコピーやcloneしたい

自分用のメモ。

Cloneメソッドを自分で用意するのめんどくさいなー。
できればライブラリ使って簡単にコピーしたいなー。

って思ったら、簡単にできたので、共有。

ディープコピーで調べるとすぐ出てくるのに、Cloneで調べると頑張って自作するタイプの記事しか出てこなかったです。

シャローコピー、ディープコピーとは

深くは書きません。

アドレスだけコピーするのがシャローコピー。
中身をコピーするのがディープコピー。

基本的にはコピーと言ってシャローコピーを求められることはなく、ディープコピーが求められます。 初心者のころはこの違いが分からずに、よく事故ってました。

改めて調べた時にシャローコピーという名前が出てこなかったので、自分のために残します。

環境およびライブラリ

  • Java
  • org.Apache.commons.lang3.SerializationUtils

制約

  • 対象のクラスにjava.io.Serializableを継承していること
  • transientを使っていないこと
    • わざわざtransient(一時的)と書いてるのだからコピーできなくて当たり前…。
      しかも、transient使ってないのってテストもできないんですね。初めて知りました。

なんとなく、自動生成したオブジェクトってjava.io.Serializableを継承している気がします。
あと、ライブラリのドメインをそのまま使おうとするとSerializableを継承してないこともあると思います。 例えば、MyBatis等のPageとか。

まぁ、そもそもアーキの思想として、ライブラリのドメインを色んな所で使っちゃダメなんですが。

実装方法

対象クラスがSerializeを継承していれば、これだけ。
Apacheライブラリはやっぱり便利なの多いですね…。

// 変換方法
SerializationUtils.clone(コピー対象のオブジェクト);
public class ReturnHistory implements Serializable {
  private String id;
  private LocalDateTime date;
}

@Test
public void データをコピーする() {
    ReturnHistory expect = 
    new ReturnHistory("100", LocalDateTime.MAX);

    ReturnHistory actual = SerializationUtils.clone(expect);

    assertThat(actual).isEqualTo(expect);
}

なおJacksonライブラリでは…

Jacksonライブラリを使うと、Serializeを継承せずとも使用できる。
という触れ込みを見たので、こちらでも検証しようとしました。

ただ、LocalDateTimeが上手くデシリアライズできなかったので、これは個人的には使えません。

検証ソースは残しているので、興味があればどうぞ。

Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at …

GitHubソース

https://github.com/hirotoKirimaru/cucumber-sample

検証ソース

CloneTests.java

https://github.com/hirotoKirimaru/cucumber-sample/blob/4848e5cab5ea80e49f263befaec4c78db929c523/src/test/java/jp/co/kelly/biz/domain/CloneTests.java

定型文

もしこの記事が役に立ったのであれば、はてぶ、Twitterでの記事の拡散、twitterのフォローもよろしくお願いします。

※ youtuberみたいに、高評価、チャンネル登録よろしくお願いします。
という一文を載せると、反応がもらえるのかテスト。