Kotlinのdata classはとても便利だけど,微妙にかゆいところに手が届かないときもあるね,という話.
TL;DR (長い! 3行で!)
- data classにbyte配列を格納したい
- でもtoString()に配列の中身が全部表示されて,logcat1行文のバッファにすら入り切らん
- 配列を格納するだけの別classを作って入れ子にしてやるといい感じ
はじめに
Kotlinのdata classで撮影した写真のJPEG Bufferと保存先File名やMeta Dataなど一式を格納するようなコンテナクラス↓を作って,Kotlinのdata classはラクでいいなぁと思ってました.
data class PhotoData(val filepath: String, val jpeg: ByteArray, val meta: String) {
}
しかし,保存ThreadでPhotoData#toString()を使ってLog出力をしたところ,
のように,byteひとつひとつがIntに変換されて,全要素が表示されるようになっていて,配列の終端かlogcatの1行文のバッファがなくなるかまで表示されてしまいます.
JPEGデータが同一なのか別モノなのか,が知りたいだけなのに,さすがにコレでは困るのでなんとかしよう,というお話です.
やりたいこと
data class にbyte配列などを格納したときでも,配列全部を表示するのでなく,配列が同一のものなのか別モノなのか,が分かる程度にtoString()でヨロシクlog出力したい.
Kotlinのdata classがJavaにどう変換されているか?
というわけで,data classで自動生成されているtoString()がJAVA変換後にどういうCodeになっているかを見てみます.
↓ のサイトを参考に,KotlinのCodeをJAVAに変換してみます.
http://tech.actindi.net/2016/12/15/kotlin.html
data class PhotoData(val filepath: String, val jpegBuffer: ByteArray) {
}
このdata class内に自動生成されるtoString()のCodeはJAVAに変換後,↓ のようになります.
public final class PhotoData
{
public String toString()
{
return (new StringBuilder())
.append("PhotoData(fileFullPath=")
.append(fileFullPath)
.append(", jpegBuffer=")
.append(Arrays.toString(jpegBuffer))
.append(")")
.toString();
}
}
このなかの
Arrays.toString(jpegBuffer)
が配列全出しの要因のようですね.
Array#toString()の仕様を調べると,↓ のようになっていて,byteひとつひとつをStringBuilder使って文字列に詰めています.
public static String toString(byte[] array) {
if (array == null) {
return "null";
}
if (array.length == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder(array.length * 6);
sb.append('[');
sb.append(array[0]);
for (int i = 1; i < array.length; i++) {
sb.append(", ");
sb.append(array[i]);
}
sb.append(']');
return sb.toString();
}
byte配列かArraysか何かに細工して挙動変えられないかなーと思ってたのですが,無理そうですね.
(じつはできるぜ! みたいなのあったら知りたいです!)
ByteArrayを格納するためだけのclassを作る
byte配列を素のままdata classに格納するとArrays#toString()が使われてしまうので,いっそ配列だけを格納するclassを別に作って入れ子にして,そのclassのtoString()をoverrideしてやれば,byte配列がそのまま出力されることを回避できるはず.
↓ こんな感じ
class ByteBuffer(val buffer: ByteArray) {
override fun toString(): String {
return "${buffer.hashCode()}"
}
}
data class PhotoData(val fileFullPath: String, val jpeg: ByteBuffer) {
}
PhotoData(
fileFullPath=/storage/emulated/0/2017-07-29_151933.JPG,
jpeg=164835622
)
ってな感じの出力になって,同じ配列かどうか判定ができる程度のいい感じのlog catになっています.
まとめ
data classに長い配列を入れた時でも,log catが荒らされることが無いようにすることができました.
Kotlinのdata classはとても便利なのにArrayを入れたときのtoString()の標準挙動だけは残念な感じですね.
他にもっといい方法がありそうなきがするなーと思いつつ.
---///