Jackson: utilizzare le annotations @JsonIgnore e @JsonProperty per escludere una proprietà solo dalla deserializzazione JSON

Nell’articolo precedente abbiamo visto come e dove utilizzare l’annotation @JsonIgnore di Jackson per escludere una proprietà di un oggetto Java dal processo di serializzazione JSON. Non essendo disponibile, il valore di tale proprietà, in fase di deserializzazione, verrà settato al valore di default previsto dal suo tipo. In questo caso quindi, il processo è simmetrico, nel senso che il valore della proprietà viene ignorato da entrambe le operazioni.
Nel caso in cui si abbia esigenza di rendere la cosa asimmettrica, cioè di escludere una proprietà dell’oggetto Java solo in fase di deserializzazione ma di includere invece il suo valore in fase di serializzazione JSON occorre utilizzare un’opportuna combinazione delle annotations @JsonIgnore e @JsonProperty. Per la precisione occorre:

  • annotare con @JsonIgnore la proprietà
  • annotare con @JsonIgnore il relativo metodo set
  • annotare con @JsonProperty il relativo metodo get

Riprendiamo l’esempio già utilizzato nel post precedente e vediamo come configurare la classe MyTestClass in modo che il campo “forgetThisField” venga serializzato nella stringa JSON ma il suo valore venga poi ignorato in fase di deserializzazione.

import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

class MyTestClass {

    private long id;
    private String name;
    private String notInterstingMember;
    private int anotherMember;

    @JsonIgnore
    private int forgetThisField;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @JsonIgnore
    public String getNotInterstingMember() {
        return this.notInterstingMember;
    }

    public void setNotInterstingMember(String notInterstingMember) {
        this.notInterstingMember = notInterstingMember;
    }

    public int getAnotherMember() {
        return this.anotherMember;
    }

    public void setAnotherMember(int anotherMember) {
        this.anotherMember = anotherMember;
    }

    @JsonProperty
    public int getForgetThisField() {
        return this.forgetThisField;
    }

    @JsonIgnore
    public void setForgetThisField(int forgetThisField) {
        this.forgetThisField = forgetThisField;
    }

    @Override
    public String toString() {
        return "MyTestClass [" + this.id + " , " +  this.name + ", " + this.notInterstingMember + ", " + this.anotherMember + ", " + this.forgetThisField + "]";
    }
}

public class JSONIgnorePropTest {

    public static void main(String[] args) {

        ObjectMapper mapper = new ObjectMapper();

        MyTestClass mtc = new MyTestClass();
        mtc.setId(1);
        mtc.setName("Test program");
        mtc.setNotInterstingMember("Don't care about this");
        mtc.setAnotherMember(100);
        mtc.setForgetThisField(999);

        String s = null;
        try {
            s = mapper.writeValueAsString(mtc);
        }
        catch (JsonProcessingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(s);

        MyTestClass mtc2 = null;
        try {
            mtc2 = mapper.readValue(s, MyTestClass.class);
        }
        catch (JsonParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (JsonMappingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(mtc2.toString());

    }
}

Come abbiamo visto in precedenza è stato necessario:

  • annotare con @JsonIgnore la proprietà “forgetThisField”
  • @JsonIgnore
    private int forgetThisField;
    
  • annotare con @JsonIgnore il relativo metodo set, “setForgetThisField”
  • @JsonIgnore
    public void setForgetThisField(int forgetThisField) {
    	this.forgetThisField = forgetThisField;
    }
    
  • annotare con @JsonProperty il relativo metodo get, “getForgetThisField”
  • @JsonProperty
    public int getForgetThisField() {
    	return this.forgetThisField;
    }
    

Eseguendo il programma di test otteniamo il seguente risultato:

{"id":1,"name":"Test program","anotherMember":100,"forgetThisField":999}
MyTestClass [1 , Test program, null, 100, 0]

Come possiamo vedere, in fase di serializzazione viene inclusa la proprietà “forgetThisField” con il suo valore 999, mentre nel nuovo oggetto istanziato deserializzando la stringa, questa proprietà viene ignorata ed il suo valore risulta essere il valore di default del suo tipo, cioè 0 essendo un int.

La cosa importante da considerare è che le annotations devono essere messe tutte esattamente come indicato. Se se ne omette qualcuna di quelle indicate, non si ottiene il risultato desiderato. Se, ad esempio, mettiamo solo l’annotation @JsonIgnore sul metodo set e l’annotation @JsonProperty sul metodo get, ma non mettiamo @JsonIgnore sulla proprietà, essa non viene ignorata in fase di deserializzazione:

class MyTestClass {

    private long id;
    private String name;
    private String notInterstingMember;
    private int anotherMember;
	
    //@JsonIgnore    			// COMMENTED
    private int forgetThisField;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @JsonIgnore
    public String getNotInterstingMember() {
        return this.notInterstingMember;
    }

    public void setNotInterstingMember(String notInterstingMember) {
        this.notInterstingMember = notInterstingMember;
    }

    public int getAnotherMember() {
        return this.anotherMember;
    }

    public void setAnotherMember(int anotherMember) {
        this.anotherMember = anotherMember;
    }

    @JsonProperty
    public int getForgetThisField() {
        return this.forgetThisField;
    }

    @JsonIgnore
    public void setForgetThisField(int forgetThisField) {
        this.forgetThisField = forgetThisField;
    }

    @Override
    public String toString() {
        return "MyTestClass [" + this.id + " , " +  this.name + ", " + this.notInterstingMember + ", " + this.anotherMember + ", " + this.forgetThisField + "]";
    }

}

Eseguendo nuovamente il programma otteniamo:

{"id":1,"name":"Test program","anotherMember":100,"forgetThisField":999}
MyTestClass [1 , Test program, null, 100, 999]

Come possiamo vedere questa volta la proprietà non è stata ignorata in fase di deserializzazione ed il valore serializzato viene quindi settato nel nuovo oggetto.

Allo stesso modo, se mettiamo l’annotation @JsonIgnore sulla proprietà e l’annotation @JsonProperty sul metodo get ma non mettiamo il @JsonIgnore sul metodo set ancora una volta l’indicazione di ignorare la proprietà non viene propagata alla deserializzazione:

class MyTestClass {

    private long id;
    private String name;
    private String notInterstingMember;
    private int anotherMember;

    @JsonIgnore
    private int forgetThisField;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @JsonIgnore
    public String getNotInterstingMember() {
        return this.notInterstingMember;
    }

    public void setNotInterstingMember(String notInterstingMember) {
        this.notInterstingMember = notInterstingMember;
    }

    public int getAnotherMember() {
        return this.anotherMember;
    }

    public void setAnotherMember(int anotherMember) {
        this.anotherMember = anotherMember;
    }

    @JsonProperty
    public int getForgetThisField() {
        return this.forgetThisField;
    }

    // @JsonIgnore					// COMMENTED
    public void setForgetThisField(int forgetThisField) {
        this.forgetThisField = forgetThisField;
    }

    @Override
    public String toString() {
        return "MyTestClass [" + this.id + " , " +  this.name + ", " + this.notInterstingMember + ", " + this.anotherMember + ", " + this.forgetThisField + "]";
    }
}
{"id":1,"name":"Test program","anotherMember":100,"forgetThisField":999}
MyTestClass [1 , Test program, null, 100, 999]

One thought on “Jackson: utilizzare le annotations @JsonIgnore e @JsonProperty per escludere una proprietà solo dalla deserializzazione JSON

  1. Pingback: Jackson JSON: differenza tra le annotations @JsonIgnore e @JsonIgnoreProperties | Dede Blog

Leave a Reply

Your email address will not be published. Required fields are marked *