Jak określić Jacksona, aby używał tylko pól - najlepiej globalnie

191

Domyślne zachowanie jackona wydaje się używać zarówno właściwości (pobierających i ustawiających), jak i pól do serializacji i deserializacji do json.

Chciałbym użyć tych pól jako kanonicznego źródła konfiguracji serializacji i dlatego nie chcę, aby Jackson w ogóle patrzył na właściwości.

Mogę to zrobić indywidualnie dla każdej klasy z adnotacją:

 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)

Ale nie chcę umieszczać tego na każdej klasie ...

Czy można to skonfigurować globalnie? Jak dodać trochę do Mapera obiektów?

Michael Wiles
źródło
1
Tim udzielił dobrej odpowiedzi. Inną możliwością jest to, że jeśli masz wspólną klasę podstawową, możesz do niej dodać adnotacje klasowe; adnotacje są dziedziczone przez Jacksona.
StaxMan,
1
Myślę, że próbowałem, ale wydaje się, że musisz powiedzieć podklasom, aby użyły tego, co definiuje przypadek podstawowy ...
Michael Wiles,
2
Nie, chyba że podklasa zastępuje adnotację klasy, adnotacje rodzica są widoczne tak, jakby były częścią definicji podklasy (jeśli nie, byłby to błąd). JDK nie musi tak traktować adnotacji, ale Jackson implementuje pełne dziedziczenie adnotacji (nawet adnotacji metod).
StaxMan,
Uwaga na INFER_PROPERTY_MUTATORSflagę. Wymusza widoczność seterów, jeśli jest widoczny getter lub pole.
Ondra Žižka
I inni .
Ondra Žižka

Odpowiedzi:

157

Możesz skonfigurować poszczególnych ObjectMapperów w następujący sposób:

ObjectMapper mapper  = new ObjectMapper();
mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));

Jeśli chcesz ustawić globalnie, zwykle uzyskuję dostęp do skonfigurowanego mapera poprzez klasę opakowania.

Tim Helmstedt
źródło
3
Dobrze, chociaż myślę, że może być konieczne ustawienie kontrolera (metody Xxx () zwykle tworzą nowy obiekt). Więc coś w stylu „mapper.setVisibilityChecker (mapper.getVisibilityChecker (). Z ...);”
StaxMan,
@StaxMan dobre połączenie na setVisibilityChecker, edytowałem odpowiedź, aby odzwierciedlić.
Kevin Bowersox
42
withGetterVisibilitynie obejmuje is*metod, ale jest withIsGetterVisibilitydla nich.
qerub
13
setVisibilityCheckerjest przestarzałe. Użyj setVisibilityzamiast tego.
0x7d7b
1
Właśnie tego potrzebowałem! Ta konfiguracja pozwoliła mi użyć Mixin do łatwej konwersji jednostek Hibernacji na DTO. Domyślnie ObjectMapper serializuje wszystko, a Mixin musiałby określić, które właściwości należy zignorować (tj. Odjęcie zamiast przecięcia).
TastyWheat
150

W Jackson 2.0 i nowszych możesz po prostu użyć:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;   

...

ObjectMapper mapper = new ObjectMapper();    
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

aby wyłączyć automatyczne wykrywanie.

lukk
źródło
1
Cześć wszystkim, używam słoika Jackson 1.9.0. Dostaję dodatkową właściwość json, serializując obiekt do ciągu json. Potrzebuję uzyskać ciąg json, który zawiera tylko wspomniane zmienne z @JsonProperty. Czy możesz mi pomóc w tej sprawie?
jrhamza
7
Możesz zacząć od adnotacji klasy wspomnianej w pytaniu OP: @JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)Następnie musisz opatrzyć adnotacjami każdą właściwość, którą chcesz dołączyć@JsonProperty
lukk
Dzięki! Wcześniej znalazłem wiele przykładów kodu, do których odwoływano się do JsonMethod zamiast PropertyAccessor. Jeśli szukasz JsonMethod, rzadko otrzymujesz linki do PropertyAccessor, a następnie ... Jaki jest najlepszy sposób na znalezienie nazw klas zastępczych w artefaktach następczych? Czy może być twardy i paskudny, nie?
philburns
38

Specjalnie dla osób boolean is*()pobierających:

Spędziłem dużo czasu na tym, dlaczego nie poniżej

  @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)

ani to

  setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE);
  setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
  setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

pracował dla mojego Boolean Getter / Setter.

Rozwiązanie jest proste:

  @JsonAutoDetect(isGetterVisibility = Visibility.NONE, ...          
  setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);

AKTUALIZACJA: Spring-boot dozwolone skonfigurować:

jackson:
  visibility.field: any
  visibility.getter: none
  visibility.setter: none
  visibility.is-getter: none

Zobacz Wspólne właściwości aplikacji # JACKSON

Grigorij Kislin
źródło
1
Czy możesz wyjaśnić, jak proste rozwiązanie należy zastosować do klasy fasoli?
Pavel Niedoba
1
Dziękuję Ci. To znaczy Getter uratował mi dzień.
uśmiechnij się
To nie jest odpowiedź na pytanie i jest raczej mylące.
Ondra Žižka
14

dla jackson 1.9.10 używam

ObjectMapper mapper = new ObjectMapper();

mapper.setVisibility(JsonMethod.ALL, Visibility.NONE);
mapper.setVisibility(JsonMethod.FIELD, Visibility.ANY);

włączyć automatyczne dedukcje.

mfe
źródło
2
Oto jest sposób. Dzięki.
cuneytykaya
Zastanawiam się, czy jest jakaś różnica między zrobieniem tego a wyłączeniem „automatycznego wykrywania”.
ksenoterracid
10

Co powiesz na to: użyłem go z mixinem

obiekt niezgodny

@Entity
@Getter
@NoArgsConstructor
public class Telemetry {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long pk;
    private String id;
    private String organizationId;
    private String baseType;
    private String name;
    private Double lat;
    private Double lon;
    private Instant updateTimestamp;
}

Mixin:

@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
public static class TelemetryMixin {}

Stosowanie:

    ObjectMapper om = objectMapper.addMixIn(Telemetry.class, TelemetryMixin.class);
    Telemetry[] telemetries = om.readValue(someJson, Telemetry[].class);

Nic nie mówi, że nie można przewidzieć żadnej liczby klas i zastosować tego samego miksu.

Jeśli nie jesteś zaznajomiony z mixinami, są one po prostu koncepcyjnie: struktura mixin jest super narzucona klasie docelowej (według Jacksona, nie w odniesieniu do JVM).

Christian Bongiorno
źródło
3

Jeśli chcesz zrobić to globalnie, nie martwiąc się o konfigurację swojego ObjectMapper, możesz utworzyć własną adnotację:

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonAutoDetect(
        getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
        setterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE,
        creatorVisibility = JsonAutoDetect.Visibility.NONE
)
public @interface JsonExplicit {
}

Teraz musisz po prostu adnotować swoje zajęcia @JsonExpliciti możesz iść!

Przeprowadź także edycję powyższego wywołania, aby @JsonAutoDetectupewnić się, że masz ustawione wartości odpowiadające Twojemu programowi.

Kredyt dla https://stackoverflow.com/a/13408807 dla pomagając mi dowiedzieć się o@JacksonAnnotationsInside

retodaredevil
źródło
3

Jeśli używasz Spring Boot, możesz skonfigurować Jackson globalnie w następujący sposób:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class JacksonObjectMapperConfiguration implements Jackson2ObjectMapperBuilderCustomizer {

    @Override
    public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
        jacksonObjectMapperBuilder.visibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
        jacksonObjectMapperBuilder.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        jacksonObjectMapperBuilder.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY);
    }

}
Czasy
źródło