Jackson pokonuje podkreślenia na korzyść obudowy wielbłąda

160

Pobieram ciąg JSON z Internetu; jak większość JSON, widziałem, że zawiera długie klucze, które są oddzielone podkreśleniami. Zasadniczo moim celem jest deserializacja JSON w obiekty java, ale nie używam podkreślenia w kodzie java.

Na przykład, mogę mieć Userklasę z firstNamepolem w przypadku wielbłąda, jednocześnie muszę jakoś powiedzieć Jacksonowi, aby zamapował first_nameklucz z JSON na firstNamepole klasy. Czy to możliwe?

class User{
    protected String firstName;
    protected String getFirstName(){return firstName;}
}
user1384991
źródło

Odpowiedzi:

103

Powinieneś użyć @JsonPropertypola, na którym chcesz zmienić domyślne mapowanie nazw.

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

Więcej informacji: API

Alex
źródło
86
Nie rób tego, bo inaczej będziesz musiał to zrobić dla każdej nieruchomości. Zobacz odpowiedź thehpi poniżej.
Ryan Shillington,
Udało mi się dodać adnotację tylko do jednej właściwości, ale zmieniło to kolejność właściwości w wygenerowanym ciągu: właściwości z adnotacjami pojawiły się jako ostatnie. (Jackson
2.3.0
1
@RyanShillington - Popraw mnie, jeśli się mylę, ale to jedyna opcja, jeśli ciąg JSON, z którego analizujesz, nie używa spójnego formatu, tj. Używa zarówno camelCase, jak i podkreślenia?
DavidR
@DavidR Zgadza się. Zakładam, że nie możesz naprawić danych źródłowych? To jest do bani.
Ryan Shillington
@PaulTsai ok, więc nie krępuj się ich używać :)
Alex
351

Możesz skonfigurować ObjectMapperkonwersję wielkości wielbłądów na nazwy z podkreśleniem:

objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

Lub dodaj adnotację do określonej klasy modelu za pomocą tej adnotacji:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

Przed Jacksonem 2.7 stała nosiła nazwę:

PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
thehpi
źródło
5
Zauważ, że zostało to wprowadzone tylko w Jackson 1.9.
David Moles,
62
@deprecated Od wersji 2.7 zamiast tego użyj SNAKE_CASE;
Thermech,
1
jeden qq: czy kiedy używam strategii nazewnictwa snake_case, pliki json z podkreśleniami będą deserializowane do obudowy wielbłąda?
Ram Patra,
2
@Ramswaroop Tak, to sprawia, że ​​Jackson zarówno mówi, jak i oczekuje snake_case
Drew Stephens
1
@Ramswaroop Dla mnie z Jacksonem 2.7.3 i właściwościami z adnotacją @JsonProperty(nazwa wywnioskowana z normalnych camelCasewłaściwości Javy) PropertyNamingStrategy.SNAKE_CASEspowodowała, że ​​deserializacja przestała działać z camelCase JSON (tak jak wcześniej) i wymagała snake_case.
Drew Stephens
119

Jeśli jest to aplikacja uruchamiana wiosną, w pliku application.properties po prostu użyj

spring.jackson.property-naming-strategy = SNAKE_CASE

Lub Opisz klasę modelu tą adnotacją.

@JsonNaming (PropertyNamingStrategy.SnakeCaseStrategy.class)

adam.smithsonian01
źródło
3
Jeśli dodam do mojej klasy adnotację „@JsonNaming (PropertyNamingStrategy.SnakeCaseStrategy.class)”, to działa. Ale jeśli użyję „spring.jackson.property-naming-strategy = SNAKE_CASE” w „application.properties”, nie będzie. Używam „Spring Boot (v2.0.0.BUILD-SNAPSHOT)”. Czy masz jakies pomysły ?
Bruno
1
to samo tutaj, spring.jackson.property-naming-strategy=SNAKE_CASEnie działa, używam Spring Boot 2.0
soulmachine
1
to samo tutaj, spring.jackson.property-naming-strategy = SNAKE_CASE nie działa, używam Spring Boot 2.0.5. Ale używanie adnotacji działa dla mnie
Neo Pham
Może Twój ObjectMappernie jest tworzony wiosną? Utwórz klasę @Configuration z metodą @Bean, która zwraca ObjectMapper. Nie jestem pewien, czy jest to konieczne.
Ondra Žižka
48

Jeśli chcesz to dla pojedynczej klasy, możesz użyć PropertyNamingStrategy z @JsonNaming , coś takiego:

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

    String businessName;
    String businessLegalName;

}

Zostanie serializowany do:

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

Od w zastąpiona , dlatego należy używać:Jackson 2.7LowerCaseWithUnderscoresStrategySnakeCaseStrategy

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

    String businessName;
    String businessLegalName;

}
Arturo Volpe
źródło
29

Powyższe odpowiedzi dotyczące @JsonPropertyi CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORESsą w 100% dokładne, chociaż niektórzy ludzie (tacy jak ja) mogą próbować to zrobić wewnątrz aplikacji Spring MVC z konfiguracją opartą na kodzie. Oto przykładowy kod (który mam w środku Beans.java), aby osiągnąć zamierzony efekt:

@Bean
public ObjectMapper jacksonObjectMapper() {
    return new ObjectMapper().setPropertyNamingStrategy(
            PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
}
Dawngerpony
źródło
9
Alternatywa dla Spring Boot, jeśli używasz Spring Boot <= 1.3, w application.propertiesadd spring.jackson.property-naming-strategy=CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCOR‌​ES. W przypadku Spring Boot 1.4 użyj spring.jackson.property-naming-strategy=SNAKE_CASEzamiast tego.
Dump Cake
1
@zapl tak, masz rację, prawdopodobnie wspomniałem o wersji Jacksona zamiast wersji spring-boot. Pozwolę sobie usunąć ten komentarz, aby uniknąć nieporozumień.
Ram Patra
1
Od wersji 2.7 Jacksona jest to SNAKE_CASE. To zadziałało dla mnie: final ObjectMapper objectMapper = new ObjectMapper().setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE);
Jonathan
12

Obecnie najlepszą praktyką jest skonfigurowanie Jacksona w application.yml(lubproperties pliku ).

Przykład:

spring:
  jackson:
    property-naming-strategy: SNAKE_CASE

Jeśli masz bardziej złożone wymagania konfiguracyjne, możesz również skonfigurować Jacksona programowo.

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
źródło
Czy wiesz, czy masz inne wystąpienie ładowania jackson2objectmapper i nadpisywanie tego? Czy możesz potwierdzić, że nawet ta fasola jest ładowana?
Kenny Cason
Daj także wir rozwiązaniu DuffJ. Jest całkiem podobnie.
Kenny Cason,
Myślę, że poprawianie właściwości jest właściwą drogą; i również zalecane. Robi to samo co to.
WesternGun
@WesternGun dobre połączenie. Jeśli to możliwe, robię to za pomocą yaml / properties.
Kenny Cason,
6

Poniżej znajduje się kilka odpowiedzi wskazujących obie strategie dla 2 różnych wersji biblioteki Jacksona:

Dla Jacksona 2.6. *

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

Dla Jackson 2.7. *

ObjectMapper objMapper = new ObjectMapper(new JsonFactory()); // or YAMLFactory()
objMapper.setNamingStrategy(
     PropertyNamingStrategy.SNAKE_CASE);
Amit Kaneria
źródło
ponownie wycofali niektóre wartości, teraz mają KEBAB_CASE, yum!
Kalpesh Soni
FTR: kebab-case is not snake_case ;-)
René