Come specificare jackson per usare solo i campi, preferibilmente a livello globale


192

Il comportamento del jackon predefinito sembra utilizzare sia proprietà (getter e setter) sia campi per serializzare e deserializzare su json.

Vorrei usare i campi come fonte canonica di configurazione della serializzazione e quindi non voglio che Jackson guardasse le proprietà.

Posso farlo su una classe individuale con l'annotazione:

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

Ma non voglio metterlo su ogni singola classe ...

È possibile configurarlo a livello globale? Ti piace aggiungerne un po 'a Object Mapper?


1
Tim ha dato una buona risposta. Un'altra possibilità è che se si dispone di una classe base comune, è possibile inserire annotazioni di classe in quella classe; le annotazioni sono ereditate da Jackson.
StaxMan,

1
Penso di aver provato, ma sembra che tu debba dire alle sottoclassi di usare ciò che definisce il caso base ...
Michael Wiles,

2
No, a meno che la sottoclasse non sovrascriva l'annotazione della classe, le annotazioni del genitore sono visibili come se facessero parte della definizione della sottoclasse (in caso contrario, si tratterebbe di un bug). Questo non è necessariamente il modo in cui JDK gestisce le annotazioni, ma Jackson implementa la piena eredità per le annotazioni (anche per le annotazioni del metodo).
StaxMan,

Attenzione alla INFER_PROPERTY_MUTATORSbandiera. Forza la visibilità dei setter se c'è un getter o un campo visibile.
Ondra Žižka,

Risposte:


157

Puoi configurare singoli ObjectMapper in questo modo:

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

Se vuoi che sia impostato a livello globale, di solito accedo a un mappatore configurato tramite una classe wrapper.


3
Bene, anche se penso che potrebbe essere necessario impostare anche il checker (con i metodi withXxx () di solito si crea un nuovo oggetto). Quindi qualcosa come 'mapper.setVisibilityChecker (mapper.getVisibilityChecker (). With ...);'
StaxMan,

@StaxMan buona chiamata su setVisibilityChecker, ho modificato la risposta per riflettere.
Kevin Bowersox,

42
withGetterVisibilitynon copre i is*metodi, ma c'è withIsGetterVisibilityper loro.
qerub,

13
setVisibilityCheckerè deprecato. Usa setVisibilityinvece.
0x7d7b

1
Questo è proprio quello di cui avevo bisogno! Questa configurazione mi ha permesso di utilizzare un Mixin per convertire facilmente entità ibernate in DTO. Per impostazione predefinita, ObjectMapper serializza tutto e un Mixin dovrebbe specificare quali proprietà ignorare (ovvero una sottrazione anziché un'intersezione).
TastyWheat,

150

In Jackson 2.0 e versioni successive puoi semplicemente usare:

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

per disattivare il rilevamento automatico.


1
Ciao ragazzi, sto usando il vaso Jackson 1.9.0. Ricevo ulteriori proprietà json, mentre sto serializzando l'oggetto su una stringa json. Devo ottenere la stringa JSON, che contiene solo variabili menzionate con @JsonProperty. Potete per favore aiutarmi su questo?
jrhamza,

7
Puoi iniziare con l'annotazione di classe menzionata nella domanda OP: @JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)Successivamente, devi annotare ogni proprietà che vuoi includere con@JsonProperty
lukk

Grazie! In precedenza, ho trovato molti esempi di codice in cui si faceva riferimento a JsonMethod anziché a PropertyAccessor. Se cerchi JsonMethod, raramente ottieni collegamenti a PropertyAccessor, allora ... Qual è il modo migliore per trovare i nomi delle classi sostitutive negli artefatti successivi? Può essere duro e cattivo, no?
Philburns,

38

In particolare per i boolean is*()getter:

Ho trascorso molto tempo sul perché né sotto

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

né questo

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

ha lavorato per il mio Getter / Setter booleano.

La soluzione è semplice:

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

AGGIORNAMENTO: avvio a molla consentito configurarlo:

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

Vedi Proprietà comuni dell'applicazione # JACKSON


1
Potresti elaborare la soluzione semplice da applicare alla classe bean?
Pavel Niedoba,

1
Grazie. Cioè, Getter mi ha salvato la giornata.
grinch

Questa non è una risposta alla domanda ed è piuttosto fuorviante.
Ondra Žižka,

14

per jackson 1.9.10 che uso

ObjectMapper mapper = new ObjectMapper();

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

per disattivare la deduzione automatica.


2
Questo è il modo. Grazie.
cuneytykaya,

mi chiedo se ci sia qualche differenza tra fare questo e disabilitare il "rilevamento automatico".
xenoterracide,

10

Che ne dici di questo: l'ho usato con un mixin

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

Uso:

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

Non c'è nulla che dica che non puoi prevedere un numero qualsiasi di classi e applicare lo stesso mixin.

Se non hai familiarità con i mixin, sono concettualmente semplicemente: la struttura del mixin è super imposta alla classe target (secondo Jackson, non per quanto riguarda la JVM).


3

Se vuoi un modo per farlo a livello globale senza preoccuparti della configurazione del tuo ObjectMapper, puoi creare la tua annotazione:

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

Ora devi solo annotare le tue lezioni @JsonExplicite sei a posto!

Assicurati anche di modificare la chiamata sopra per @JsonAutoDetectassicurarti di avere i valori impostati su ciò che funziona con il tuo programma.

Ringraziamo https://stackoverflow.com/a/13408807 per avermi aiutato a scoprire@JacksonAnnotationsInside


3

Se usi Spring Boot, puoi configurare Jackson a livello globale come segue:

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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.