Jackson databind 열거형 대소문자를 구분하지 않음
대소문자를 구분하지 않는 열거값을 포함하는 JSON 문자열을 직렬화 해제하려면 어떻게 해야 합니까?(Jackson Databind 사용)
JSON 문자열:
[{"url": "foo", "type": "json"}]
그리고 자바 POJO:
public static class Endpoint {
public enum DataType {
JSON, HTML
}
public String url;
public DataType type;
public Endpoint() {
}
}
이 경우 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();
}
그리고 그것은 성공하였다.근데 이게 해킹처럼 보여서 더 좋은 솔루투온이 없을까 해서요.
커스텀 디시리얼라이저도 쓸 수 있지만, enum을 사용하는 POJO가 많아서 유지보수가 어렵습니다.
적절한 명명 규칙을 사용하여 Enum을 시리얼화 및 역직렬화하는 더 좋은 방법을 제안할 수 있는 사람이 있습니까?
java의 enum을 소문자로 하고 싶지 않습니다!
사용한 테스트 코드는 다음과 같습니다.
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.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;
}
}
Jackson 2.6 이후로는 다음과 같이 간단하게 할 수 있습니다.
public enum DataType {
@JsonProperty("json")
JSON,
@JsonProperty("html")
HTML
}
버전 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);
}
}
출력:
["json","html"]
[JSON, HTML]
스프링 부츠를 사용하는 경우2.1.x
잭슨과 함께2.9
다음 애플리케이션 속성을 사용할 수 있습니다.
spring.jackson.mapper.accept-case-insensitive-enums=true
나는 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;
}
}
GET 파라미터에서 Enum 무시 대소문자를 역직렬화하려는 사용자에게는 ACCEPT_CASE_INSECTIVE_ENUMS를 활성화해도 아무런 효과가 없습니다.이 옵션은 신체 직위 해제에만 효과가 있기 때문에 도움이 되지 않습니다.대신 다음을 시도해 보십시오.
public class StringToEnumConverter implements Converter<String, Modes> {
@Override
public Modes convert(String from) {
return Modes.valueOf(from.toUpperCase());
}
}
그리고 나서.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToEnumConverter());
}
}
답변 및 코드 샘플은 여기서 가져옵니다.
잭슨의 Enum을 대소문자를 구분하지 않고 역직렬화할 수 있도록 하려면 다음 속성을 단순히application.properties
스프링 부트 프로젝트 파일을 참조하십시오.
spring.jackson.mapper.accept-case-insensitive-enums=true
속성 파일의 yaml 버전이 있는 경우 아래 속성을 다음 파일에 추가합니다.application.yml
파일.
spring:
jackson:
mapper:
accept-case-insensitive-enums: true
@Constantin Zyubin에게 사과드리며, 그의 답변은 제가 필요로 하는 것에 가까웠지만, 저는 그것을 이해하지 못했습니다.그래서 저는 다음과 같이 생각합니다.
하지 않는수 없는 , 할 수 .StdConverter
은 이 하여 합니다.JsonDeserialize
석입니니다다
예를 들어:
public class ColorHolder {
public enum Color {
RED, GREEN, BLUE
}
public static final class ColorParser extends StdConverter<String, Color> {
@Override
public Color convert(String value) {
return Arrays.stream(Color.values())
.filter(e -> e.getName().equalsIgnoreCase(value.trim()))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Invalid value '" + value + "'"));
}
}
@JsonDeserialize(converter = ColorParser.class)
Color color;
}
문제는 com.fasterxml.jackson.databind.util로 관련지어져 있습니다.Enum Resolver.HashMap을 사용하여 열거값을 유지하며 HashMap은 대소문자를 구분하지 않는 키를 지원하지 않습니다.
위의 답변에서는 모든 문자를 대문자 또는 소문자로 해야 합니다.에넘의 모든 민감한 문제를 해결했습니다.
https://gist.github.com/bhdrk/02307ba8066d26fa1537
CustomDeserializers.java
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.std.EnumDeserializer;
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
import com.fasterxml.jackson.databind.util.EnumResolver;
import java.util.HashMap;
import java.util.Map;
public class CustomDeserializers extends SimpleDeserializers {
@Override
@SuppressWarnings("unchecked")
public JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config, BeanDescription beanDesc) throws JsonMappingException {
return createDeserializer((Class<Enum>) type);
}
private <T extends Enum<T>> JsonDeserializer<?> createDeserializer(Class<T> enumCls) {
T[] enumValues = enumCls.getEnumConstants();
HashMap<String, T> map = createEnumValuesMap(enumValues);
return new EnumDeserializer(new EnumCaseInsensitiveResolver<T>(enumCls, enumValues, map));
}
private <T extends Enum<T>> HashMap<String, T> createEnumValuesMap(T[] enumValues) {
HashMap<String, T> map = new HashMap<String, T>();
// from last to first, so that in case of duplicate values, first wins
for (int i = enumValues.length; --i >= 0; ) {
T e = enumValues[i];
map.put(e.toString(), e);
}
return map;
}
public static class EnumCaseInsensitiveResolver<T extends Enum<T>> extends EnumResolver<T> {
protected EnumCaseInsensitiveResolver(Class<T> enumClass, T[] enums, HashMap<String, T> map) {
super(enumClass, enums, map);
}
@Override
public T findEnum(String key) {
for (Map.Entry<String, T> entry : _enumsById.entrySet()) {
if (entry.getKey().equalsIgnoreCase(key)) { // magic line <--
return entry.getValue();
}
}
return null;
}
}
}
사용방법:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class JSON {
public static void main(String[] args) {
SimpleModule enumModule = new SimpleModule();
enumModule.setDeserializers(new CustomDeserializers());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(enumModule);
}
}
나는 Iago Ferndez와 Paul 용액의 수정을 사용했다.
요청 개체에 대소문자를 구분하지 않는 열거형이 있습니다.
@POST
public Response doSomePostAction(RequestObject object){
//resource implementation
}
class RequestObject{
//other params
MyEnumType myType;
@JsonSetter
public void setMyType(String type){
myType = MyEnumType.valueOf(type.toUpperCase());
}
@JsonGetter
public String getType(){
return myType.toString();//this can change
}
}
대소문자를 구분하지 않는 방법으로 역직렬화(질문에 게재된 코드에 근거해 작성)하고 싶을 때는, 다음과 같이 에넘을 취급합니다.
@JsonIgnore
public void setDataType(DataType dataType)
{
type = dataType;
}
@JsonProperty
public void setDataType(String dataType)
{
// Clean up/validate String however you want. I like
// org.apache.commons.lang3.StringUtils.trimToEmpty
String d = StringUtils.trimToEmpty(dataType).toUpperCase();
setDataType(DataType.valueOf(d));
}
enum이 중요하지 않아 자체 클래스에 보통 소문자 문자열을 처리하기 위해 정적 구문 분석 메서드를 추가합니다.
잭슨과의 열거형 역직렬화는 간단하다.String을 기반으로 열거형을 역직렬화하려면 열거형에 대한 생성자, getter 및 setter가 필요합니다.또한 이 열거형을 사용하는 클래스에는 DataType을 String이 아닌 param으로 수신하는 setter가 있어야 합니다.
public class Endpoint {
public enum DataType {
JSON("json"), HTML("html");
private String type;
@JsonValue
public String getDataType(){
return type;
}
@JsonSetter
public void setDataType(String t){
type = t.toLowerCase();
}
}
public String url;
public DataType type;
public Endpoint() {
}
public void setType(DataType dataType){
type = dataType;
}
}
json이 있는 경우 Jackson의 ObjectMapper를 사용하여 Endpoint 클래스로 역직렬화할 수 있습니다.
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
Endpoint endpoint = mapper.readValue("{\"url\":\"foo\",\"type\":\"json\"}", Endpoint.class);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
언급URL : https://stackoverflow.com/questions/24157817/jackson-databind-enum-case-insensitive
'source' 카테고리의 다른 글
두 날짜 사이의 날짜인지 PHP 확인 (0) | 2023.01.27 |
---|---|
"select from" 구문을 사용하지 않고 MySQL 테이블이 존재하는지 확인하시겠습니까? (0) | 2023.01.27 |
React의 useState()는 무엇입니까? (0) | 2023.01.27 |
WAMP에서 MySql을 MariaDb로 대체하는 방법 (0) | 2023.01.27 |
MARIADB: 범위에 조인된 선택 항목에는 인덱스가 사용되지 않습니다. (0) | 2023.01.27 |