Como posso desserializar a string JSON que contém valores enum que não diferenciam maiúsculas de minúsculas? (usando Jackson Databind)
A string JSON:
[{"url": "foo", "type": "json"}]
e meu Java POJO:
public static class Endpoint {
public enum DataType {
JSON, HTML
}
public String url;
public DataType type;
public Endpoint() {
}
}
neste caso, desserializar o JSON com "type":"json"
falharia onde "type":"JSON"
funcionaria. Mas eu quero "json"
trabalhar também por motivos de convenção de nomenclatura.
Serializar o POJO também resulta em letras maiúsculas "type":"JSON"
Pensei em usar @JsonCreator
e @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();
}
E funcionou. Mas eu queria saber se há uma solução melhor, porque isso parece um hack para mim.
Também posso escrever um desserializador personalizado, mas tenho muitos POJOs diferentes que usam enums e seria difícil de manter.
Alguém pode sugerir uma maneira melhor de serializar e desserializar enums com a convenção de nomenclatura adequada?
Não quero que meus enums em java sejam minúsculos!
Aqui está um código de teste que usei:
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));
Respostas:
Na versão 2.4.0, você pode registrar um serializador personalizado para todos os tipos de Enum ( link para o problema do github). Além disso, você pode substituir o desserializador Enum padrão por conta própria, que estará ciente do tipo de Enum. Aqui está um exemplo:
Resultado:
fonte
Jackson 2.9
Isso agora é muito simples, usando
jackson-databind
2.9.0 e superiorExemplo completo com testes
fonte
jackson-databind
2.9.2 funciona especificamente como esperado.spring.jackson.mapper.accept-case-insensitive-enums=true
Eu encontrei esse mesmo problema em meu projeto, decidimos construir nossos enums com uma chave de string e usar
@JsonValue
e um construtor estático para serialização e desserialização, respectivamente.fonte
DataType.valueOf(key.toUpperCase())
- caso contrário, você realmente não mudou nada. Codificando defensivamente para evitar um NPE:return (null == key ? null : DataType.valueOf(key.toUpperCase()))
key
campo é desnecessário. EmgetKey
, você poderia apenasreturn name().toLowerCase()
Desde o Jackson 2.6, você pode simplesmente fazer isso:
Para um exemplo completo, veja esta essência .
fonte
Optei pela solução de Sam B., mas uma variante mais simples.
fonte
DataType.valueOf(key.toUpperCase())
é uma instanciação direta onde você tem um loop. Isso poderia ser um problema para um enum muito numeroso. Claro,valueOf
pode lançar uma IllegalArgumentException, que seu código evita, portanto, é um bom benefício se você preferir a verificação nula à verificação de exceção.Se estiver usando Spring Boot
2.1.x
com Jackson,2.9
você pode simplesmente usar esta propriedade do aplicativo:spring.jackson.mapper.accept-case-insensitive-enums=true
fonte
Para aqueles que tentam desserializar Enum ignorando maiúsculas e minúsculas nos parâmetros GET , habilitar ACCEPT_CASE_INSENSITIVE_ENUMS não vai adiantar nada. Não vai ajudar porque essa opção só funciona para desserialização do corpo . Em vez disso, tente isto:
e depois
A resposta e os exemplos de código são daqui
fonte
Com minhas desculpas a @Konstantin Zyubin, sua resposta foi quase o que eu precisava - mas não entendi, então é assim que acho que deveria ser:
Se você deseja desserializar um tipo de enum como não diferencia maiúsculas de minúsculas - ou seja, você não deseja, ou não pode modificar o comportamento de todo o aplicativo, você pode criar um desserializador personalizado apenas para um tipo - por subclassificação
StdConverter
e força Jackson para usá-lo apenas nos campos relevantes usando aJsonDeserialize
anotação.Exemplo:
fonte
O problema é relatado para com.fasterxml.jackson.databind.util.EnumResolver . ele usa HashMap para manter valores enum e HashMap não oferece suporte a chaves que não diferenciam maiúsculas de minúsculas.
nas respostas acima, todos os caracteres devem ser maiúsculos ou minúsculos. mas corrigi todos os problemas (in) sensíveis para enums com isso:
https://gist.github.com/bhdrk/02307ba8066d26fa1537
CustomDeserializers.java
Uso:
fonte
Usei uma modificação da solução de Iago Fernández e Paul.
Eu tinha um enum em meu objeto de solicitação que não diferenciava maiúsculas de minúsculas
fonte
Para permitir a desserialização sem distinção entre maiúsculas e minúsculas de enums em jackson, basta adicionar a propriedade abaixo ao
application.properties
arquivo do seu projeto de inicialização.Se você tiver a versão yaml do arquivo de propriedades, adicione a propriedade abaixo ao seu
application.yml
arquivo.fonte
É assim que às vezes lido com enums quando desejo desserializar sem fazer distinção entre maiúsculas e minúsculas (com base no código postado na pergunta):
Se o enum não for trivial e, portanto, estiver em sua própria classe, geralmente adiciono um método de análise estática para lidar com Strings em minúsculas.
fonte
Desserializar enum com jackson é simples. Quando você deseja desserializar enum com base em String, precisa de um construtor, um getter e um setter para seu enum. Além disso, a classe que usa esse enum deve ter um setter que recebe DataType como parâmetro, não String:
Quando você tem seu json, pode desserializar para a classe Endpoint usando ObjectMapper de Jackson:
fonte