Jackson supera los guiones bajos a favor del caso de los camellos

160

Recupero una cadena JSON de internet; Como la mayoría de JSON que he visto, incluye teclas largas que están separadas por guiones bajos. Esencialmente, mi objetivo es deserializar JSON en objetos java, pero no uso guiones bajos en código java.

Por ejemplo, podría tener una Userclase con firstNamecampo en camello, al mismo tiempo necesito decirle a Jackson que asigne la first_nameclave de JSON al firstNamecampo de clase. ¿Es posible?

class User{
    protected String firstName;
    protected String getFirstName(){return firstName;}
}
usuario1384991
fuente

Respuestas:

103

Debe usar el @JsonPropertycampo en el que desea cambiar la asignación de nombre predeterminada.

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

Para más información: la API

Alex
fuente
86
No haga esto, de lo contrario tendrá que hacerlo para cada propiedad. Vea la respuesta de thehpi a continuación.
Ryan Shillington
Solo pude anotar una propiedad, pero cambió el orden de las propiedades en la cadena generada: las propiedades anotadas aparecieron en último lugar. (Jackson 2.3.0)
eebbesen
1
@RyanShillington - Corrígeme si me equivoco, pero esta es tu única opción si la cadena JSON desde la que estás analizando no usa un formato consistente, es decir, ¿usa camelCase y subrayado?
DavidR
@DavidR Eso es correcto. ¿Asumo que no puedes arreglar los datos de origen? Eso apesta.
Ryan Shillington
@PaulTsai ok, así que siéntete libre de usarlos :)
Alex
351

Puedes configurar el ObjectMapper para convertir el caso de camello a nombres con un guión bajo:

objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

O anote una clase de modelo específica con esta anotación:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

Antes de Jackson 2.7, la constante se llamaba:

PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
thehpi
fuente
55
Tenga en cuenta que esto solo se introdujo en Jackson 1.9.
David Moles
62
@deprecated Desde 2.7 usa SNAKE_CASE en su lugar;
Thermech
1
una qq: cuando uso la estrategia de nomenclatura snake_case, ¿se deserializarán los archivos json con guiones bajos al caso camel?
Ram Patra
2
@Ramswaroop Sí, esto hace que Jackson hable y espere snake_case
Drew Stephens
1
@Ramswaroop Para mí, con Jackson 2.7.3 y las propiedades anotadas con solo @JsonProperty(nombre inferido de las camelCasepropiedades normales de Java) PropertyNamingStrategy.SNAKE_CASEhizo que la deserialización dejara de funcionar con camelCase JSON (como había estado usando) y requiera snake_case.
Drew Stephens
119

Si es una aplicación de arranque de primavera, en el archivo application.properties, simplemente use

spring.jackson.property-naming-strategy = SNAKE_CASE

O anote la clase de modelo con esta anotación.

@JsonNaming (PropertyNamingStrategy.SnakeCaseStrategy.class)

adam.smithsonian01
fuente
3
Si anoto mi clase con el "@JsonNaming (PropertyNamingStrategy.SnakeCaseStrategy.class)" funciona. Pero si uso "spring.jackson.property-naming-strategy = SNAKE_CASE" en "application.properties" no lo hará. Estoy usando "Spring Boot (v2.0.0.BUILD-SNAPSHOT)". Tienes alguna idea ?
Bruno
1
lo mismo aquí, spring.jackson.property-naming-strategy=SNAKE_CASEno funciona, estoy usando Spring Boot 2.0
soulmachine 05 de
1
lo mismo aquí, spring.jackson.property-naming-strategy = SNAKE_CASE no funciona, estoy usando Spring Boot 2.0.5. Pero usar la anotación está funcionando para mí
Neo Pham
¿Quizás tu ObjectMapperno es creado por Spring? Cree una clase @Configuration con un método @Bean que devuelva un ObjectMapper. No estoy seguro si esto es necesario.
Ondra Žižka
48

Si desea esto para una clase única, puede usar PropertyNamingStrategy con @JsonNaming , algo así:

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

    String businessName;
    String businessLegalName;

}

Se serializará a:

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

Desde Jackson 2.7el LowerCaseWithUnderscoresStrategyen desuso en favor de SnakeCaseStrategy, por lo que debe utilizar:

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

    String businessName;
    String businessLegalName;

}
Arturo Volpe
fuente
29

Las respuestas anteriores sobre @JsonPropertyy CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORESson 100% precisas, aunque algunas personas (como yo) podrían estar tratando de hacer esto dentro de una aplicación Spring MVC con configuración basada en código. Aquí hay un código de muestra (que tengo dentro Beans.java) para lograr el efecto deseado:

@Bean
public ObjectMapper jacksonObjectMapper() {
    return new ObjectMapper().setPropertyNamingStrategy(
            PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
}
Poni del alba
fuente
9
Una alternativa para la primavera de arranque, si está utilizando la primavera de arranque <= 1,3, en el application.propertiescomplemento spring.jackson.property-naming-strategy=CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCOR‌​ES. Para Spring Boot 1.4 use spring.jackson.property-naming-strategy=SNAKE_CASEen su lugar.
Dump Cake
1
@zapl sí, tienes razón, probablemente mencioné la versión de Jackson en lugar de la versión de spring-boot. Déjame eliminar ese comentario para evitar confusiones.
Ram Patra
1
A partir de la versión 2.7 de Jackson es SNAKE_CASE. Esto funcionó para mí: final ObjectMapper objectMapper = new ObjectMapper().setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE);
Jonathan
12

La mejor práctica actual es configurar Jackson dentro de application.yml(oproperties ) archivo.

Ejemplo:

spring:
  jackson:
    property-naming-strategy: SNAKE_CASE

Si tiene requisitos de configuración más complejos, también puede configurar Jackson mediante programación.

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
fuente
¿Sabes si tienes otra instancia de jackson2objectmapper cargándose y anulando esta? ¿Y puede confirmar que incluso este bean se está cargando?
Kenny Cason
También dale un giro a la solución de DuffJ. Es bastante similar
Kenny Cason
Creo que ajustar las propiedades es la forma correcta; y recomendado también. Eso hace lo mismo que esto.
WesternGun
@WesternGun buena llamada. Tiendo a hacer esto a través de yaml / properties cuando es posible.
Kenny Cason
6

Aquí hay pocas respuestas que indican ambas estrategias para 2 versiones diferentes de la biblioteca Jackson a continuación:

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
fuente
Una vez más, desaprobaron algunos valores, ahora tienen KEBAB_CASE, ¡mmm!
Kalpesh Soni
FTR: kebab-case no es snake_case ;-)
René