Enum を JSON オブジェクトとして変換する際にPropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES を指定するとdeclaring_classプロパティが削除されない


何を言っているのか分からねーと思うが、俺も何が起きたのか分からなかった...

以下のようなEnum[^1]を`JSON Object`として変換すると・・・

[^1]: [ORACLE The Java™ Tutorials Enum Types](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html)

```java
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Planet {

    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6),
    JUPITER(1.9e+27, 7.1492e7),
    SATURN(5.688e+26, 6.0268e7),
    URANUS(8.686e+25, 2.5559e7),
    NEPTUNE(1.024e+26, 2.4746e7);

    private final double mass; // in kilograms
    private final double radius; // in meters

    private Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }

    // universal gravitational constant (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    public double getMass() {
        return mass;
    }

    public double getRadius() {
        return radius;
    }

    @JsonProperty
    public double surfaceGravity() {
        return G * mass / (radius * radius);
    }
}
```

以下のような出力になります。

```
{"mass":1.9E27,"radius":7.1492E7,"surfaceGravity":24.80617666947324}
```

デフォルトがキャメルケースなので、`PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES` を指定してスネークケースで出力されるようにしてみます。
すると・・・

```java
ObjectMapper mapper = new ObjectMapper()
    .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES)
String json = mapper.writeValueAsString(Planet.JUPITER);
System.out.println(json);
```

```
{"mass":1.9E27,"radius":7.1492E7,"surface_gravity":24.80617666947324,"declaring_class":"sample.jackson.Planet"}
```

このようにスネークケースにはなるのですが、`declaring_class` というプロパティが出力されるようになってしまいます。

一応、`BasicSerializerFactory#buildEnumSerializer(SerializationConfig, JavaType, BeanDescription)` で、拾ってきてしまった`java.lang.Enum#getDeclaringClass()`を除外しようとしているみたいなのですが・・・

```java:com.fasterxml.jackson.databind.ser.BasicSerializerFactory.java

/* As per [Issue#24], may want to use alternate shape, serialize as JSON Object.
 * Challenge here is that EnumSerializer does not know how to produce
 * POJO style serialization, so we must handle that special case separately;
 * otherwise pass it to EnumSerializer.
 */
JsonFormat.Value format = beanDesc.findExpectedFormat(null);
if (format != null && format.getShape() == JsonFormat.Shape.OBJECT) {
    // one special case: suppress serialization of "getDeclaringClass()"...
    ((BasicBeanDescription) beanDesc).removeProperty("declaringClass");
    // returning null will mean that eventually BeanSerializer gets constructed
    return null;
}
```
このようにキャメルケースでベタ書きしています。
スネークケースを指定した場合にココか動いていないようにも見えるので、非常に不安になるコードです。

```java:com.fasterxml.jackson.databind.introspect.BasicBeanDescription.java

/**
 * Method that can be used to prune unwanted properties, during
 * construction of serializers and deserializers.
 * Use with utmost care, if at all...
 * 
 * @since 2.1
 */
public boolean removeProperty(String propName)
{
    Iterator<BeanPropertyDefinition> it = _properties.iterator();
    while (it.hasNext()) {
        BeanPropertyDefinition prop = it.next();
        if (prop.getName().equals(propName)) {
            it.remove();
            return true;
        }
    }
    return false;
}
```

・・・うーん、`BeanPropertyDefinition#getName()` と比較していますが、今回の場合だと *"declaringClass"* ではなく *"declaring_class"* が設定されています。まさかとは思いましたが、結構単純なミスじゃないかと思われます。
あえて *"declaringClass"* を指定したということはStrategyに左右されなそうな`BeanPropertyDefinition#getInternalName()` を使うべきだったのではないかと。。。


```java:com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition.java

/**
 * Accessor that can be used to determine implicit name from underlying
 * element(s) before possible renaming. This is the "internal"
 * name derived from accessor ("x" from "getX"), and is not based on
 * annotations or naming strategy.
 */
public abstract String getInternalName();

```