Comment spécifier Jackson pour n'utiliser que des champs - de préférence globalement

192

Le comportement de jackon par défaut semble utiliser à la fois les propriétés (getters et setters) et les champs pour sérialiser et désérialiser en json.

Je voudrais utiliser les champs comme source canonique de la configuration de sérialisation et je ne veux donc pas que Jackson regarde du tout les propriétés.

Je peux le faire sur une base de classe individuelle avec l'annotation:

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

Mais je ne veux pas avoir à mettre ça sur chaque classe ...

Est-il possible de configurer cela globalement? Vous aimez en ajouter à l'Object Mapper?

Michael Wiles
la source
1
Tim a donné une bonne réponse. Une autre possibilité est que si vous avez une classe de base commune, vous pouvez y ajouter des annotations de classe; les annotations sont héritées par Jackson.
StaxMan
1
Je pense que j'ai essayé cela, mais il semble que vous deviez dire aux sous-classes d'utiliser ce que le cas de base définit ...
Michael Wiles
2
Non, à moins que la sous-classe ne remplace l'annotation de classe, les annotations des parents sont visibles comme si elles faisaient partie de la définition de sous-classe (sinon, ce serait un bogue). Ce n'est pas nécessairement ainsi que JDK traite les annotations, mais Jackson implémente l'héritage complet pour les annotations (même pour les annotations de méthode).
StaxMan
Méfiez-vous du INFER_PROPERTY_MUTATORSdrapeau. Il force la visibilité des setters s'il y a un getter ou un champ visible.
Ondra Žižka
Et d'autres .
Ondra Žižka

Réponses:

157

Vous pouvez configurer des ObjectMappers individuels comme ceci:

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

Si vous voulez qu'il soit défini globalement, j'accède généralement à un mappeur configuré via une classe wrapper.

Tim Helmstedt
la source
3
Bien, même si je pense que vous devrez peut-être également définir le vérificateur (les méthodes withXxx () créent généralement un nouvel objet). Donc quelque chose comme 'mapper.setVisibilityChecker (mapper.getVisibilityChecker (). With ...);'
StaxMan
@StaxMan bon appel sur setVisibilityChecker, j'ai édité la réponse pour refléter.
Kevin Bowersox le
42
withGetterVisibilityne couvre pas les is*méthodes, mais il y en a withIsGetterVisibilitypour elles.
qerub
13
setVisibilityCheckerest obsolète. Utilisez setVisibilityplutôt.
0x7d7b
1
C'est exactement ce dont j'avais besoin! Cette configuration m'a permis d'utiliser un Mixin pour convertir facilement des entités Hibernate en DTO. Par défaut, l'ObjectMapper sérialise tout et un Mixin devrait spécifier les propriétés à ignorer (c'est-à-dire une soustraction au lieu d'une intersection).
TastyWheat
150

Dans Jackson 2.0 et versions ultérieures, vous pouvez simplement utiliser:

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

pour désactiver la détection automatique.

lukk
la source
1
Salut les gars, j'utilise le pot Jackson 1.9.0. J'obtiens une propriété json supplémentaire, tout en sérialisant l'objet en chaîne json. J'ai besoin d'obtenir la chaîne json, qui ne contient que les variables mentionnées avec @JsonProperty. Pouvez-vous m'aider à ce sujet?
jrhamza
7
Vous pouvez commencer avec l'annotation de classe mentionnée dans la question OP: @JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)Ensuite, vous devez annoter chaque propriété que vous souhaitez inclure avec@JsonProperty
lukk
Merci! Avant, j'ai trouvé de nombreux exemples de code dans lesquels JsonMethod était référencé au lieu de PropertyAccessor. Si vous recherchez JsonMethod, vous obtenez rarement des liens vers PropertyAccessor alors ... Quelle est la meilleure façon de trouver des noms de classe de remplacement dans les artefacts successeurs? Peut-être dur et méchant, non?
philburns
38

Spécifiquement pour les boolean is*()getters:

J'ai passé beaucoup de temps sur pourquoi ni en dessous

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

ni ça

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

a travaillé pour mon Boolean Getter / Setter.

La solution est simple:

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

MISE À JOUR: spring-boot autorisé le configurer:

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

Voir les propriétés d'application communes # JACKSON

Grigory Kislin
la source
1
Pourriez-vous expliquer comment une solution simple devrait être appliquée à la classe de haricots?
Pavel Niedoba
1
Je vous remercie. C'est Getter qui m'a sauvé la journée.
grinch
Ceci n'est pas une réponse à la question et est plutôt trompeur.
Ondra Žižka
14

pour jackson 1.9.10 j'utilise

ObjectMapper mapper = new ObjectMapper();

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

pour désactiver la déduction automatique.

mfe
la source
2
C'est le chemin. Merci.
cuneytykaya
me demande s'il y a une différence entre faire cela et désactiver la "détection automatique".
xenoterracide
10

Que diriez-vous de ceci: je l'ai utilisé avec un mixin

objet non conforme

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

Usage:

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

Il n'y a rien qui dit que vous ne pouvez pas foreach un certain nombre de classes et appliquer le même mixin.

Si vous n'êtes pas familier avec les mixins, ils sont conceptuellement simples: la structure du mixin est superposée à la classe cible (selon jackson, pas en ce qui concerne la JVM).

Christian Bongiorno
la source
3

Si vous souhaitez un moyen de le faire globalement sans vous soucier de la configuration de votre ObjectMapper, vous pouvez créer votre propre annotation:

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

Il ne vous reste plus qu'à annoter vos cours avec @JsonExplicitet vous êtes prêt à partir!

Assurez-vous également de modifier l'appel ci-dessus pour @JsonAutoDetectvous assurer que les valeurs sont définies sur ce qui fonctionne avec votre programme.

Merci à https://stackoverflow.com/a/13408807 pour m'avoir aidé à en savoir plus@JacksonAnnotationsInside

retodaredevil
la source
3

Si vous utilisez Spring Boot, vous pouvez configurer Jackson globalement comme suit:

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

}

Fois
la source