スネークケースのJSONをJavaBeanに突っ込みたい

# 先頭1文字だけのキャメルケースがうまくいかない？
メモ書き程度に、SpringのdependencyライブラリにあるJacksonで、スネークケースJSONの場合にうまくいかなかったので検証してみます。

## ひとまず事象
```java:SampleController.java
package com.example.controller;

import com.example.resource.TestJacksonResource;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
public class SampleController {

    @GetMapping("test")
    public TestJacksonResource jackson() throws IOException {
        
        String snakeJson = "{\"i_hoge_name\":\"hoge\",\"low_fuga_name\":\"fuga\"}";
        
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

        TestJacksonResource resource = objectMapper.readValue(snakeJson, TestJacksonResource.class);

        return resource;
    }
}
```

```TestJacksonResource.java
package com.example.resource;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class TestJacksonResource implements Serializable {
    private String iHogeName;
    private String lowFugaName;
}
```

```java:実行結果
Unrecognized field "i_hoge_name" (class com.example.resource.TestJacksonResource), not marked as ignorable (2 known properties: "ihoge_name", "low_fuga_name"]) at [Source: (String)"{"i_hoge_name":"hoge","low_fuga_name":"fuga"}"; line: 1, column: 17] (through reference chain: com.example.resource.TestJacksonResource["i_hoge_name"])
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "i_hoge_name" (class com.example.resource.TestJacksonResource), not marked as ignorable (2 known properties: "ihoge_name", "low_fuga_name"])
 at [Source: (String)"{"i_hoge_name":"hoge","low_fuga_name":"fuga"}"; line: 1, column: 17] (through reference chain: com.example.resource.TestJacksonResource["i_hoge_name"])
	at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:823)
	at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1153)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1589)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1567)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:294)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
	at com.example.controller.SampleController.jackson(SampleController.java:22)
```

Jacksonにより認識されているプロパティ名がどうやら`i_hoge_name`ではなく`ihoge_name`のためマッピングできないらしい。

JavaBeanのフィールド名に`@JsonProperty`をつければ解決することはわかっているのですが、なるべくJavaBeanに手を入れたくないです。

## JavaBeanのフィールドをpublicにする
通ったけど`public`なフィールドなんていやじゃ！

## lombok使わないでprivateフィールドでアクセッサ用意してみる
```java:TestJacksonResource.java
    public String getiHogeName() {
        return iHogeName;
    }

    public String getLowFugaName() {
        return lowFugaName;
    }

    public void setiHogeName(String iHogeName) {
        this.iHogeName = iHogeName;
    }

    public void setLowFugaName(String lowFugaName) {
        this.lowFugaName = lowFugaName;
    }
```

```json:実行結果
{"iHogeName":"hoge","lowFugaName":"fuga"}
```

おぉ通った！！

## lombokの自動生成クラスをのぞいてみる
```java:TestJacksonResource.class
public String getIHogeName() {
    return this.iHogeName;
}
```
なるほど、これで原因はわかりましたね。
実装まではのぞいてませんが、Jacksonのプロパティ名を決定するロジックがアクセッサメソッドから生成するみたいですね。

`iHogeName`のアクセッサ命名って`getIHogeName`(lombok)と`getiHogeName`(intelliJの`command+N`)はどっちが正しいのでしょう。
感覚的には先頭大文字の`getIHogeName`かなぁ。。。

そもそもそんなフィールド名つけんじゃねぇー！が正解かも。

### 参考
こんなstackoverflowもありました。
[Springbootの@JsonPropertyで指定したキーでJSONを返したい](https://ja.stackoverflow.com/questions/41275/springboot%E3%81%AEjsonproperty%E3%81%A7%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F%E3%82%AD%E3%83%BC%E3%81%A7json%E3%82%92%E8%BF%94%E3%81%97%E3%81%9F%E3%81%84)
>挙動から察するに、Jacksonが「フィールド名」と、(lombokにより自動生成されている)「getter」の双方からJSONシリアライズ対象を決定しているように見受けられます(こちらによるとおそらくこの推測は正しいかと)。Spring上での設定は私には分からないのですが(前述リンク先の通り、JacksonへはObjectMapper#setVisibilityメソッドで設定可能)、フィールドアクセスのみでJSONシリアライズを行うようにすれば解消するのではないでしょうか。(Jackson2ObjectMapperBuilder bean を設定？)

## 原因はわかったけどlombok使いたいしフィールド名も変えたくない
そもそもの使い方が間違ってるから諦めますか、、、
時間があったら調べてみたいですが。

ただデシリアライズ（読み込み）時は`@JsonProperty`でいいんですけど、シリアライズ時も影響を受けるので、いい方法無いかなぁ

*  そもそもResourceクラスを共有するなという問題
*  [ControllerでのシリアライズはMessageConverterの問題](https://qiita.com/dayflower/items/67503dbe3157d13db547)