Jackson supera sublinhados a favor do caso de camelo

160

Eu recupero uma string JSON da internet; como a maioria dos JSON que eu vi, inclui chaves longas separadas por sublinhados. Essencialmente, meu objetivo é desserializar JSON em objetos java, mas não uso sublinhados no código java.

Por exemplo, eu posso ter uma Userclasse com firstNamecampo em caso de camelo, simultaneamente, preciso de alguma forma dizer a Jackson para mapear a first_namechave do JSON para o firstNamecampo da classe. É possível?

class User{
    protected String firstName;
    protected String getFirstName(){return firstName;}
}
user1384991
fonte

Respostas:

103

Você deve usar o @JsonPropertycampo no qual deseja alterar o mapeamento de nome padrão.

class User{
    @JsonProperty("first_name")
    protected String firstName;
    protected String getFirstName(){return firstName;}
}

Para mais informações: a API

Alex
fonte
86
Não faça isso, caso contrário você terá que fazê-lo para todas as propriedades. Veja a resposta do thehpi abaixo.
Ryan Shillington
Consegui anotar apenas uma propriedade, mas isso mudou a ordem das propriedades na sequência gerada: as propriedades anotadas apareceram por último. (Jackson 2.3.0)
eebbesen
1
@RyanShillington - Corrija-me se eu estiver errado, mas esta é sua única opção se a string JSON da qual você está analisando não usar um formato consistente, ou seja, usar camelCase e sublinhado?
DavidR
@ Davidid Isso está correto. Estou assumindo que você não pode corrigir os dados de origem? Isso é péssimo.
Ryan Shillington
@PaulTsai ok, então sinta-se livre para usá-los :)
Alex
351

Você pode configurar o ObjectMapperpara converter maiúsculas de minúsculas em nomes com um sublinhado:

objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

Ou anote uma classe de modelo específica com esta anotação:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

Antes de Jackson 2.7, a constante tinha o nome:

PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
thehpi
fonte
5
Observe que isso foi introduzido apenas no Jackson 1.9.
David Moles
62
@ obsoleto Desde 2.7, use SNAKE_CASE;
Thermech 21/03/16
1
um qq: quando eu uso a estratégia de nomeação snake_case, os arquivos json com sublinhados serão desserializados para camel case?
Ram Patra
2
@Ramswaroop Sim, isso faz com que Jackson falar e esperar snake_case
de Drew Stephens
1
@ Ramswaroop Para mim, com o Jackson 2.7.3 e as propriedades anotadas com just @JsonProperty(nome inferido das camelCasepropriedades normais do Java), a PropertyNamingStrategy.SNAKE_CASEdesserialização parou de funcionar com o camelCase JSON (como eu estava usando) e requer o snake_case.
Desenhou Stephens
119

Se for um aplicativo de inicialização com mola, no arquivo application.properties, use

spring.jackson.property-naming-strategy = SNAKE_CASE

Ou Anote a classe do modelo com esta anotação.

@JsonNaming (PropertyNamingStrategy.SnakeCaseStrategy.class)

adam.smithsonian01
fonte
3
Se eu anotar minha classe com o "@JsonNaming (PropertyNamingStrategy.SnakeCaseStrategy.class)", ele funcionará. Mas se eu usar "spring.jackson.property-naming-strategy = SNAKE_CASE" em "application.properties", isso não acontecerá. Estou usando o "Spring Boot (v2.0.0.BUILD-SNAPSHOT)". Você tem alguma ideia ?
de Bruno
1
mesmo aqui, spring.jackson.property-naming-strategy=SNAKE_CASEnão trabalho, eu estou usando Spring inicialização 2.0
soulmachine
1
mesmo aqui, spring.jackson.property-naming-strategy = SNAKE_CASE não funciona, estou usando o Spring Boot 2.0.5. Mas usando a anotação está trabalhando para mim
Neo Pham
Talvez o seu ObjectMappernão seja criado pelo Spring? Crie uma classe @Configuration com um método @Bean que retorne um ObjectMapper. Não tenho certeza se isso é necessário.
Ondra Žižka
48

Se você deseja isso para uma classe única, pode usar o PropertyNamingStrategy com o @JsonNaming , algo como isto:

@JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)
public static class Request {

    String businessName;
    String businessLegalName;

}

Serializará para:

{
    "business_name" : "",
    "business_legal_name" : ""
}

Como Jackson 2.7o LowerCaseWithUnderscoresStrategyin foi descontinuado em favor de SnakeCaseStrategy, você deve usar:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public static class Request {

    String businessName;
    String businessLegalName;

}
Arturo Volpe
fonte
29

As respostas acima são @JsonPropertye CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORESsão 100% precisas, embora algumas pessoas (como eu) possam estar tentando fazer isso dentro de um aplicativo Spring MVC com configuração baseada em código. Aqui está o código de exemplo (que eu tenho dentro Beans.java) para alcançar o efeito desejado:

@Bean
public ObjectMapper jacksonObjectMapper() {
    return new ObjectMapper().setPropertyNamingStrategy(
            PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
}
Dawngerpony
fonte
9
Uma alternativa para o Spring Boot, se você estiver usando o Spring Boot <= 1.3, em application.propertiesadição spring.jackson.property-naming-strategy=CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCOR‌​ES. Para o Spring Boot 1.4, use em spring.jackson.property-naming-strategy=SNAKE_CASEvez disso.
Dump bolo de
1
@zapl sim, você está certo, eu provavelmente mencionei a versão do jackson em vez da versão do spring-boot. Deixe-me excluir esse comentário para evitar confusão.
Ram Patra
1
A partir da versão 2.7 do Jackson, é SNAKE_CASE. Isso funcionou para mim: final ObjectMapper objectMapper = new ObjectMapper().setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE);
Jonathan
12

A melhor prática atual é configurar o Jackson no arquivo application.yml(ou properties).

Exemplo:

spring:
  jackson:
    property-naming-strategy: SNAKE_CASE

Se você tiver requisitos de configuração mais complexos, também poderá configurar o Jackson programaticamente.

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class JacksonConfiguration {

    @Bean
    public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
        return new Jackson2ObjectMapperBuilder()
                .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        // insert other configurations
    }

} 
Kenny Cason
fonte
Você sabe se você tem outra instância do jackson2objectmapper sendo carregada e substituindo esta? E você pode confirmar que mesmo este bean está sendo carregado?
18718 Kenny Cason
Também dê um giro na solução de DuffJ. É bem parecido.
Kenny Cason
Eu acho que ajustar as propriedades é o caminho certo; e recomendado também. Isso faz o mesmo que isso.
WesternGun 01/02/19
@WesternGun good call. Costumo fazer isso via yaml / properties quando possível.
Kenny Cason
6

Existem poucas respostas aqui indicando as duas estratégias para duas versões diferentes da biblioteca Jackson abaixo:

Para Jackson 2.6. *

ObjectMapper objMapper = new ObjectMapper(new JsonFactory()); // or YAMLFactory()
objMapper.setNamingStrategy(
     PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

Para Jackson 2.7. *

ObjectMapper objMapper = new ObjectMapper(new JsonFactory()); // or YAMLFactory()
objMapper.setNamingStrategy(
     PropertyNamingStrategy.SNAKE_CASE);
Amit Kaneria
fonte
novamente eles preteriram alguns valores, agora eles têm KEBAB_CASE, yum!
Kalpesh Soni
FTR: kebab-caso não é snake_case ;-)
René