先日、Jackson を使用した JSONシリアライズ/デシリアライズで、snake Case と camel Case の
予め存在する方法のことを書いた。。。
oboe2uran.hatenablog.com
大文字の snake Case の場合、どうするのだ!?
とレアなケースで少し頭をかかえた。
小文字の snake Case の場合から追いかけていけば、解が見つかるだろう。。。
小文字の JSONテキスト
{ "item_id" : "is1001", "serial_no" : "A20013454", "price" : 10890 }
対応クラス
import java.io.Serializable; import lombok.Data; @Data public class ItemInfo implements Serializable{ private static final long serialVersionUID = 1L; private String itemId; private String serialNo; private int price; }
PropertyNamingStrategies.SNAKE_CASE を使った変換
ObjectMapper mapper = new ObjectMapper() .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); ItemInfo info = mapper.readValue(jsontxt, ItemInfo.class); System.out.println(info);
結果標準出力
ItemInfo(itemId=is1001, serialNo=A20013454, price=10890)
問題の key が大文字の snake Case
{ "ITEM_ID" : "is1001", "SERIAL_NO" : "A20013454", "PRICE" : 10890 }
PropertyNamingStrategies.SNAKE_CASE の中身を見れば、
戻り値を toUpperCase すれば良いとすぐに判る。
ことから、コピーで自前に Strategy を用意できる。
import com.fasterxml.jackson.databind.PropertyNamingStrategies.NamingBase; /** * UpperSnakeCaseStrategy */ public class UpperSnakeCaseStrategy extends NamingBase{ @Override public String translate(String input){ if (input == null) return input; int length = input.length(); StringBuilder result = new StringBuilder(length * 2); int resultLength = 0; boolean wasPrevTranslated = false; for(int i = 0; i < length; i++){ char c = input.charAt(i); if (i > 0 || c != '_'){ if (Character.isUpperCase(c)){ if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_'){ result.append('_'); resultLength++; } c = Character.toLowerCase(c); wasPrevTranslated = true; }else{ wasPrevTranslated = false; } result.append(c); resultLength++; } } return resultLength > 0 ? result.toString().toUpperCase() : input; } }
以下のように setPropertyNamingStrategy で指定すれば良い。
ObjectMapper mapper = new ObjectMapper() .setPropertyNamingStrategy(new UpperSnakeCaseStrategy());
同じことに悩んだ人は必ずいるはずで、ネット検索すると、、、
https://www.deep-rain.com/programming/java/949#SNAKE_CASE
なるほど、PropertyNamingStrategy を継承して、
Google Guavaを利用してlowerCamelをUpperSnakeCaseに変換
すれば良いのか。。。
でも、com.google.common.base.CaseFormat をインポートすることになり
Google Guava に依存してしまうので、短く書けても、どうなのかなあ。。。
まあ、どちらの方法も、Java → JSON も同じで、可逆性がちゃんとあるのだけれど。。。