大文字の snake Case を camel Case 規則の Java オブジェクトに変換する

先日、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 に依存してしまうので、短く書けても、どうなのかなあ。。。
まあ、どちらの方法も、JavaJSON も同じで、可逆性がちゃんとあるのだけれど。。。