Converter nomes de propriedades de estilo JSON em nomes Java CamelCase com GSON

107

Estou usando o GSON para converter dados JSON que recebo em um objeto Java. Funciona muito bem em todos os meus testes. O problema é que nossos objetos reais têm algumas propriedades nomeadas como is_online. GSON apenas os mapeia se eles forem nomeados totalmente iguais, seria bom ter GSON convertendo os nomes para Java camel case isOnline.

Parece que isso é possível durante a criação dos dados JSON, caso camelo é convertido em palavras separadas por sublinhado em JSON. Mas não consigo encontrar uma maneira de especificar isso ao contrário.

Janusz
fonte
5
Proponho aceitar uma resposta
JeanValjean

Respostas:

313

Descobri que a configuração a seguir funciona perfeitamente ao ler json com atributos sublinhados e usar camelcasing em meus modelos.

Gson gson = new GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .create()
Hampei
fonte
2
Ótima resposta, obrigado! @janusz, se alguma dessas respostas ajudou você, marque-as como Resposta aceita.
sufinawaz
1
Se você tiver um caso em que o nome contém dois sublinhados, ele ignorará o primeiro sublinhado. Ex. this_key_has__two_underscores será convertido para thisKeyHas_TwoUnderscores e vice-versa. O ponto principal é a FieldNamingPolicy, onde o enum diz "minúsculas" com sublinhados, enquanto aqui o nome convertido tem maiúsculas com sublinhado (_T).
Deepak GM
Muito simples, evita que eu tenha que fazer anotações em um monte de campos!
William T. Mallard
99

Você pode usar a SerializedNameanotação:

@SerializedName("field_name_in_json")
private final String fieldNameInJava;

Nota: Quando você já tiver definido um FieldNamingPolicy, SerializedNameo substituirá suas configurações para aquele campo específico (bastante útil para casos especiais).

saschoar
fonte
2

Tenha em mente que seu exemplo é um caso extremo. Se você tem uma propriedade 'foo', seu getter deve ser nomeado como 'getFoo', e se você tem uma propriedade chamada 'foo_bar', seu getter deve ser chamado de 'getFooBar', no entanto, em seu exemplo você está mapeando um booleano e os booleanos têm convenções de nomenclatura de casos especiais em java. Uma propriedade booleana primitiva chamada online deve ter um getter chamado 'isOnline', NÃO 'getOnline' ou ainda pior, 'getIsOnline'. Um objeto wrapper booleano (ou seja, booleano) não deve seguir este caso especial e uma propriedade chamada 'online' deve ter um getter chamado 'getOnline'.

Portanto, ter propriedades booleanas com 'is' no nome é um caso extremo, em que você desejará remover esse prefixo específico durante a conversão. Na direção inversa, seu código pode querer inspecionar o objeto json tanto para um nome de propriedade bruto quanto para uma versão 'is_XXX'.

Jherico
fonte
2

Acho que o que você quer está aqui . Usando anotações, você pode dizer ao GSON que o mySuperCoolField é na verdade chamado this_field_is_fun no JSON e ele o descompactará corretamente. Pelo menos acho que funciona para desserialização também.

Se isso não funcionar, você pode usar o JsonSerializer / JsonDeserializers personalizado, que funciona muito bem, mas é necessário atualizá-los para alterações em sua classe (como quando você adiciona um campo). Você perde a magia automática.

A coisa mais fácil de fazer (o que seria feio, mas muito limpo e simples se a primeira sugestão não funcionar) seria simplesmente nomear o campo de forma a deixar GSON feliz e adicionar métodos acessadores extras com os nomes que você gosta , por exemplo

public boolean isXXX() {return this.is_XXX;}
MBCook
fonte
o mais fácil é o que estou fazendo no momento e funciona muito bem. Todo o código com o estilo java feio e não típico está escondido nas classes de dados e ninguém de fora vai vê-lo. Mas ainda está me incomodando um pouco :)
Janusz,