tom*_*136 80 java enums serialization json jackson
如何反序列化包含不区分大小写的枚举值的JSON字符串?(使用Jackson Databind)
JSON字符串:
[{"url": "foo", "type": "json"}]
Run Code Online (Sandbox Code Playgroud)
和我的Java POJO:
public static class Endpoint {
public enum DataType {
JSON, HTML
}
public String url;
public DataType type;
public Endpoint() {
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,反序列化JSON "type":"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();
}
Run Code Online (Sandbox Code Playgroud)
它奏效了.但我想知道是否有更好的解决方案,因为这看起来像是对我的黑客攻击.
我也可以编写一个自定义反序列化器,但是我有很多不同的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));
Run Code Online (Sandbox Code Playgroud)
dav*_*wil 100
杰克逊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
Run Code Online (Sandbox Code Playgroud)
测试的完整示例
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Sam*_*rry 73
我在我的项目中遇到了同样的问题,我们决定使用字符串键构建我们的枚举,并分别使用@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;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 37
从Jackson 2.6开始,您可以简单地执行此操作:
public enum DataType {
@JsonProperty("json")
JSON,
@JsonProperty("html")
HTML
}
Run Code Online (Sandbox Code Playgroud)
有关完整示例,请参阅此要点.
Ale*_*lov 33
在2.4.0版中,您可以为所有Enum类型注册自定义序列化程序(链接到github问题).此外,您可以自行更换标准的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);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
["json","html"]
[JSON, HTML]
Run Code Online (Sandbox Code Playgroud)
lin*_*nqu 29
我选择了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;
}
}
Run Code Online (Sandbox Code Playgroud)
etS*_*ngh 12
如果您将Spring Boot 2.1.x
与Jackson一起2.9
使用,则可以简单地使用以下应用程序属性:
spring.jackson.mapper.accept-case-insensitive-enums=true
对于那些试图反序列化 Enum 忽略GET 参数中的大小写的人,启用 ACCEPT_CASE_INSENSITIVE_ENUMS 不会有任何好处。它无济于事,因为此选项仅适用于body deserialization。而是试试这个:
public class StringToEnumConverter implements Converter<String, Modes> {
@Override
public Modes convert(String from) {
return Modes.valueOf(from.toUpperCase());
}
}
Run Code Online (Sandbox Code Playgroud)
进而
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToEnumConverter());
}
}
Run Code Online (Sandbox Code Playgroud)
答案和代码示例来自这里
要允许在 Jackson 中对枚举进行不区分大小写的反序列化,只需将以下属性添加到application.properties
Spring Boot 项目的文件中即可。
spring.jackson.mapper.accept-case-insensitive-enums=true
Run Code Online (Sandbox Code Playgroud)
如果您有 yaml 版本的属性文件,请将以下属性添加到您的application.yml
文件中。
spring:
jackson:
mapper:
accept-case-insensitive-enums: true
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
46151 次 |
最近记录: |