So legen Sie fest, dass Jackson nur Felder verwendet - vorzugsweise global

189

Das Standardverhalten von jackon scheint sowohl Eigenschaften (Getter und Setter) als auch Felder zum Serialisieren und Deserialisieren in json zu verwenden.

Ich möchte die Felder als kanonische Quelle für die Serialisierungskonfiguration verwenden und möchte daher nicht, dass Jackson die Eigenschaften überhaupt betrachtet.

Ich kann dies auf individueller Klassenbasis mit der Anmerkung tun:

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

Aber ich möchte das nicht auf jede einzelne Klasse anwenden müssen ...

Ist es möglich, dies global zu konfigurieren? Möchten Sie dem Object Mapper etwas hinzufügen?

Michael Wiles
quelle
1
Tim gab eine gute Antwort. Eine andere Möglichkeit besteht darin, dass Sie, wenn Sie eine gemeinsame Basisklasse haben, dieser Klasse Klassenanmerkungen hinzufügen können. Anmerkungen werden von Jackson geerbt.
StaxMan
1
Ich glaube, ich habe das versucht, aber es scheint, dass Sie den Unterklassen sagen müssen, dass sie das verwenden sollen, was der Basisfall definiert ...
Michael Wiles
2
Nein, sofern die Unterklasse die Klassenanmerkungen nicht überschreibt, sind die Anmerkungen der Eltern sichtbar, als wären sie Teil der Unterklassendefinition (wenn nicht, wäre dies ein Fehler). Dies ist nicht unbedingt der Umgang von JDK mit Annotationen, aber Jackson implementiert die vollständige Vererbung für Annotationen (auch für Methodenanmerkungen).
StaxMan
Vorsicht vor der INFER_PROPERTY_MUTATORSFlagge. Es erzwingt die Sichtbarkeit von Setzern, wenn ein sichtbarer Getter oder ein sichtbares Feld vorhanden ist.
Ondra Žižka
Und andere .
Ondra Žižka

Antworten:

157

Sie können einzelne ObjectMapper wie folgt konfigurieren:

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));

Wenn Sie möchten, dass es global festgelegt wird, greife ich normalerweise über eine Wrapper-Klasse auf einen konfigurierten Mapper zu.

Tim Helmstedt
quelle
3
Gut, obwohl ich denke, dass Sie möglicherweise auch den Prüfer festlegen müssen (mit Xxx () -Methoden wird normalerweise ein neues Objekt erstellt). Also so etwas wie 'mapper.setVisibilityChecker (mapper.getVisibilityChecker (). With ...);'
StaxMan
@StaxMan guten Anruf bei setVisibilityChecker, ich habe die Antwort bearbeitet, um zu reflektieren.
Kevin Bowersox
42
withGetterVisibilitybehandelt keine is*Methoden, aber es gibt withIsGetterVisibilityfür sie.
Qerub
13
setVisibilityCheckerist veraltet. Verwenden Sie setVisibilitystattdessen.
0x7d7b
1
Das ist genau das, was ich brauchte! Diese Konfiguration ermöglichte es mir, ein Mixin zu verwenden, um Hibernate-Entitäten einfach in DTOs zu konvertieren. Standardmäßig serialisiert der ObjectMapper alles und ein Mixin müsste angeben, welche Eigenschaften ignoriert werden sollen (dh eine Subtraktion anstelle einer Kreuzung).
TastyWheat
150

In Jackson 2.0 und höher können Sie einfach Folgendes verwenden:

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);

um die automatische Erkennung auszuschalten.

lukk
quelle
1
Hallo Leute, ich benutze Jackson 1.9.0 jar. Ich erhalte eine zusätzliche json-Eigenschaft, während ich das Objekt in einen json-String serialisiere. Ich brauche den JSON-String, der nur die genannten Variablen mit @JsonProperty enthält. Können Sie mir bitte dabei helfen?
Jrhamza
7
Sie können mit der in der OP-Frage erwähnten Klassenanmerkung beginnen: @JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)Als Nächstes müssen Sie jede Eigenschaft, die Sie einschließen möchten, mit Anmerkungen versehen@JsonProperty
lukk
Vielen Dank! Zuvor habe ich viele Codebeispiele gefunden, in denen auf JsonMethod anstelle von PropertyAccessor verwiesen wurde. Wenn Sie nach JsonMethod suchen, erhalten Sie selten Links zu PropertyAccessor. Was ist der beste Weg, um Ersatzklassennamen in Nachfolge-Artefakten zu finden? Kann hart und böse sein, nein?
Philburns
38

Speziell für boolean is*()Getter:

Ich habe viel Zeit damit verbracht, warum weder unten

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

noch das

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

arbeitete für meinen Boolean Getter / Setter.

Die Lösung ist einfach:

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

UPDATE: Spring-Boot erlaubt konfigurieren:

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

Siehe Allgemeine Anwendungseigenschaften # JACKSON

Grigory Kislin
quelle
1
Können Sie erläutern, wie einfach die Lösung auf die Bean-Klasse angewendet werden sollte?
Pavel Niedoba
1
Danke dir. Das heißt, Getter hat mir den Tag gerettet.
grinch
Dies ist keine Antwort auf die Frage und eher irreführend.
Ondra Žižka
14

für jackson 1.9.10 benutze ich

ObjectMapper mapper = new ObjectMapper();

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

um die automatische Widmung auszuschalten.

mfe
quelle
2
Das ist der Weg. Vielen Dank.
Cuneytykaya
Ich frage mich, ob es einen Unterschied zwischen diesem Vorgang und dem Deaktivieren der "automatischen Erkennung" gibt.
Xenoterracide
10

Wie wäre es damit: Ich habe es mit einem Mixin verwendet

nicht konformes Objekt

@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 {}

Verwendung:

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

Es gibt nichts, was besagt, dass Sie nicht für jede Anzahl von Klassen vorgehen und das gleiche Mixin anwenden können.

Wenn Sie nicht vertraut mit Mixins sind, dann sind sie vom Konzept her einfach: Die Struktur des mixin ist Super auferlegt auf der Zielklasse (nach jackson, nicht so weit wie die JVM betroffen ist ).

Christian Bongiorno
quelle
3

Wenn Sie dies global tun möchten, ohne sich um die Konfiguration Ihrer zu kümmern ObjectMapper, können Sie Ihre eigene Anmerkung erstellen:

@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 {
}

Jetzt müssen Sie nur noch Ihre Klassen mit Anmerkungen versehen @JsonExplicitund los geht's!

@JsonAutoDetectStellen Sie außerdem sicher, dass Sie den obigen Aufruf bearbeiten , um sicherzustellen, dass die Werte auf das eingestellt sind, was mit Ihrem Programm funktioniert.

Dank an https://stackoverflow.com/a/13408807 für die Unterstützung bei der Suche nach Informationen@JacksonAnnotationsInside

retodaredevil
quelle
3

Wenn Sie Spring Boot verwenden, können Sie Jackson wie folgt global konfigurieren :

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);
    }

}
Mal
quelle