大文字と小文字を区別しない列挙値を含むJSON文字列をデシリアライズするにはどうすればよいですか? (Jackson Databindを使用)
JSON文字列:
[{"url": "foo", "type": "json"}]
および私のJava POJO:
public static class Endpoint {
public enum DataType {
JSON, HTML
}
public String url;
public DataType type;
public Endpoint() {
}
}
この場合、"type":"json"
を使用してJSONを逆シリアル化すると、"type":"JSON"
が機能する場合に失敗します。しかし、命名規則上の理由から、"json"
も同様に機能させたいです。
POJOのシリアル化も大文字"type":"JSON"
になります
@JsonCreator
と@JsonGetterを使用することを考えました:
@JsonCreator
private Endpoint(@JsonProperty("name") String url, @JsonProperty("type") String type) {
this.url = url;
this.type = DataType.valueOf(type.toUpperCase());
}
//....
@JsonGetter
private String getType() {
return type.name().toLowerCase();
}
そしてそれは働いた。しかし、これは私にとってハックのように見えるので、より良い解決策があるかどうか疑問に思っていました。
また、カスタムデシリアライザーを作成することもできますが、enumを使用するさまざまなPOJOがあり、保守が困難です。
誰かが適切な命名規則で列挙型をシリアル化および逆シリアル化するより良い方法を提案できますか?
Javaの列挙型を小文字にしたくない!
私が使用したいくつかのテストコードは次のとおりです。
String data = "[{\"url\":\"foo\", \"type\":\"json\"}]";
Endpoint[] arr = new ObjectMapper().readValue(data, Endpoint[].class);
System.out.println("POJO[]->" + Arrays.toString(arr));
System.out.println("JSON ->" + new ObjectMapper().writeValueAsString(arr));
バージョン2.4.0では、すべてのEnumタイプにカスタムシリアライザーを登録できます( link github issue)。また、Enum型を認識する標準のEnumデシリアライザを独自に置き換えることができます。以下に例を示します。
public class JacksonEnum {
public static enum DataType {
JSON, HTML
}
public static void main(String[] args) throws IOException {
List<DataType> types = Arrays.asList(JSON, HTML);
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<Enum> modifyEnumDeserializer(DeserializationConfig config,
final JavaType type,
BeanDescription beanDesc,
final JsonDeserializer<?> deserializer) {
return new JsonDeserializer<Enum>() {
@Override
public Enum deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
Class<? extends Enum> rawClass = (Class<Enum<?>>) type.getRawClass();
return Enum.valueOf(rawClass, jp.getValueAsString().toUpperCase());
}
};
}
});
module.addSerializer(Enum.class, new StdSerializer<Enum>(Enum.class) {
@Override
public void serialize(Enum value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString(value.name().toLowerCase());
}
});
mapper.registerModule(module);
String json = mapper.writeValueAsString(types);
System.out.println(json);
List<DataType> types2 = mapper.readValue(json, new TypeReference<List<DataType>>() {});
System.out.println(types2);
}
}
出力:
["json","html"]
[JSON, HTML]
ジャクソン2.9
これはjackson-databind
2.9.0以降を使用して非常に簡単になりました
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
// objectMapper now deserializes enums in a case-insensitive manner
テスト付きの完全な例
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
private enum TestEnum { ONE }
private static class TestObject { public TestEnum testEnum; }
public static void main (String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
try {
TestObject uppercase =
objectMapper.readValue("{ \"testEnum\": \"ONE\" }", TestObject.class);
TestObject lowercase =
objectMapper.readValue("{ \"testEnum\": \"one\" }", TestObject.class);
TestObject mixedcase =
objectMapper.readValue("{ \"testEnum\": \"oNe\" }", TestObject.class);
if (uppercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize uppercase value");
if (lowercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize lowercase value");
if (mixedcase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize mixedcase value");
System.out.println("Success: all deserializations worked");
} catch (Exception e) {
e.printStackTrace();
}
}
}
私は自分のプロジェクトでこの同じ問題に遭遇しました。文字列キーで列挙型を構築し、@JsonValue
と静的コンストラクターをそれぞれシリアル化と逆シリアル化に使用することにしました。
public enum DataType {
JSON("json"),
HTML("html");
private String key;
DataType(String key) {
this.key = key;
}
@JsonCreator
public static DataType fromString(String key) {
return key == null
? null
: DataType.valueOf(key.toUpperCase());
}
@JsonValue
public String getKey() {
return key;
}
}
ジャクソン2.6以降では、これを簡単に行うことができます。
public enum DataType {
@JsonProperty("json")
JSON,
@JsonProperty("html")
HTML
}
完全な例については、 this Gist を参照してください。
Sam B。の解決策を探しましたが、より単純なバリアントです。
public enum Type {
PIZZA, Apple, PEAR, SOUP;
@JsonCreator
public static Type fromString(String key) {
for(Type type : Type.values()) {
if(type.name().equalsIgnoreCase(key)) {
return type;
}
}
return null;
}
}
ジャクソン2.1.x
でSpring Boot 2.9
を使用している場合は、次のアプリケーションプロパティを使用できます。
spring.jackson.mapper.accept-case-insensitive-enums=true
IagoFernándezand Paulソリューションの修正版を使用しました。
Requestobjectに大文字と小文字を区別する必要がある列挙型がありました
@POST
public Response doSomePostAction(RequestObject object){
//resource implementation
}
class RequestObject{
//other params
MyEnumType myType;
@JsonSetter
public void setMyType(String type){
MyEnumType.valueOf(type.toUpperCase());
}
@JsonGetter
public String getType(){
return myType.toString();//this can change
}
}