Kiedy używana jest właściwość @JsonProperty i do czego służy?

183

Ten stan „fasoli” fasoli:

public class State {

    private boolean isSet;

    @JsonProperty("isSet")
    public boolean isSet() {
        return isSet;
    }

    @JsonProperty("isSet")
    public void setSet(boolean isSet) {
        this.isSet = isSet;
    }

}

jest wysyłany przewodowo za pomocą wywołania zwrotnego „sukces” ajax:

        success : function(response) {  
            if(response.State.isSet){   
                alert('success called successfully)
            }

Czy wymagana jest tutaj adnotacja @JsonProperty? Jaka jest zaleta korzystania z niego? Myślę, że mogę usunąć tę adnotację bez powodowania żadnych skutków ubocznych.

Czytając o tej adnotacji na https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations Nie wiem, kiedy należy z niej skorzystać?

niebieskie niebo
źródło

Odpowiedzi:

238

Oto dobry przykład. Używam go do zmiany nazwy zmiennej, ponieważ JSON pochodzi ze .Netśrodowiska, w którym właściwości zaczynają się od dużej litery.

public class Parameter {
  @JsonProperty("Name")
  public String name;
  @JsonProperty("Value")
  public String value; 
}

To poprawnie analizuje do / z JSON:

"Parameter":{
  "Name":"Parameter-Name",
  "Value":"Parameter-Value"
}
OldCurmudgeon
źródło
1
Czy zmienne składowe String nie mogą zostać zmienione na poprawną wielkość liter, więc publiczna nazwa String; staje się publiczną Nazwa ciągu; ?
błękitne niebo,
14
Tak, mogą, ale w środowisku Java, które sprawia, że ​​nie są zgodne ze standardami kodowania. Bardziej chodzi o moją pedanterię niż o prawdziwy problem z kodowaniem, ale jest to dobry, ale prosty przykład prawdziwego wykorzystania @JsonPropertyadnotacji.
OldCurmudgeon,
Czy tej adnotacji można użyć dla elementu typu Double? Zastanawiam się tylko, czy musi to być Stringtyp, czy jakikolwiek typ obsługiwany przez JSON? Czy może to być dowolny typ? @OldCurmudgeon
Dreamer
3
@Dreamer Tak. Ten typ jest nieistotny. Wpływa to tylko na nazwę .
OldCurmudgeon
1
@Pavan - To nie będzie miało nic wspólnego z nazewnictwem. Myślę, że powinieneś zbadać swoich seterów.
OldCurmudgeon
44

Myślę, że OldCurmudgeon i StaxMan są poprawne, ale oto odpowiedź na jedno zdanie z prostym przykładem dla ciebie.

@JsonProperty (nazwa), mówi Jackson ObjectMapper, aby odwzorował nazwę właściwości JSON na nazwę pola Java z adnotacją.

//example of json that is submitted 
"Car":{
  "Type":"Ferrari",
}

//where it gets mapped 
public static class Car {
  @JsonProperty("Type")
  public String type;
 }
grepit
źródło
Czy nazwa klasy powinna być taka sama jak element główny JSON. To mi nie działa.
Pavan
39

cóż za to, co jest teraz warte ... JsonProperty jest również używany do określania metod pobierających i ustawiających dla zmiennej oprócz zwykłej serializacji i deserializacji. Załóżmy na przykład, że masz taki ładunek:

{
  "check": true
}

i klasa Deserializer:

public class Check {

  @JsonProperty("check")    // It is needed else Jackson will look got getCheck method and will fail
  private Boolean check;

  public Boolean isCheck() {
     return check;
  }
}

Następnie w tym przypadku należy wykonać adnotację JsonProperty. Jeśli jednak masz również metodę w klasie

public class Check {

  //@JsonProperty("check")    Not needed anymore
  private Boolean check;

  public Boolean getCheck() {
     return check;
  }
}

Zajrzyj również do tej dokumentacji: http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonProperty.html

Richeek
źródło
15

Bez adnotacji wywnioskowana nazwa właściwości (pasująca do JSON) byłaby „ustawiona”, a nie - jak się wydaje intencją - „isSet”. Wynika to z faktu, że zgodnie ze specyfikacją Java Beans metody w postaci „isXxx” i „setXxx” oznaczają, że istnieje właściwość logiczna „xxx” do zarządzania.

StaxMan
źródło
1
To jest poprawna odpowiedź na konkretny przypadek podany w pytaniu
Andrew Spencer,
6

Jak wiecie, chodzi o serializację i odsalanie obiektu. Załóżmy, że istnieje obiekt:

public class Parameter {
  public String _name;
  public String _value; 
}

Serializacja tego obiektu to:

{
  "_name": "...",
  "_value": "..."
}

Nazwa zmiennej służy bezpośrednio do serializacji danych. Jeśli masz zamiar usunąć systemowy interfejs API z implementacji systemu, w niektórych przypadkach musisz zmienić nazwę zmiennej podczas serializacji / deserializacji. @JsonProperty to metadane informujące serializator o sposobie szeregowania obiektów. Służy do:

  • nazwa zmiennej
  • dostęp (CZYTAĆ, PISAĆ)
  • domyślna wartość
  • wymagane / opcjonalne

z przykładu:

public class Parameter {
  @JsonProperty(
        value="Name",
        required=true,
        defaultValue="No name",
        access= Access.READ_WRITE)
  public String _name;
  @JsonProperty(
        value="Value",
        required=true,
        defaultValue="Empty",
        access= Access.READ_WRITE)
  public String _value; 
}
Mostafa
źródło
6

Dodanie JsonProperty zapewnia również bezpieczeństwo na wypadek, gdyby ktoś zdecydował, że chce zmienić jedną z nazw właściwości, które nie zdają sobie sprawy, że dana klasa zostanie serializowana do obiektu Json. Jeśli zmienią nazwę właściwości, JsonProperty zapewnia, że ​​zostanie ona użyta w obiekcie Json, a nie nazwa właściwości.

arush436
źródło
3

Oprócz innych odpowiedzi @JsonPropertyadnotacja jest naprawdę ważna, jeśli używasz @JsonCreatoradnotacji w klasach, które nie mają konstruktora bez arg.

public class ClassToSerialize {

    public enum MyEnum {
        FIRST,SECOND,THIRD
    }

    public String stringValue = "ABCD";
    public MyEnum myEnum;


    @JsonCreator
    public ClassToSerialize(MyEnum myEnum) {
        this.myEnum = myEnum;
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        ClassToSerialize classToSerialize = new ClassToSerialize(MyEnum.FIRST);
        String jsonString = mapper.writeValueAsString(classToSerialize);
        System.out.println(jsonString);
        ClassToSerialize deserialized = mapper.readValue(jsonString, ClassToSerialize.class);
        System.out.println("StringValue: " + deserialized.stringValue);
        System.out.println("MyEnum: " + deserialized.myEnum);
    }
}

W tym przykładzie jedyny konstruktor jest oznaczony jako @JsonCreator, dlatego Jackson użyje tego konstruktora do utworzenia instancji. Ale wynik jest jak:

Serialized: {„stringValue”: „ABCD”, „myEnum”: „FIRST”}

Wyjątek w wątku „main” com.fasterxml.jackson.databind.exc.InvalidFormatException: Nie można skonstruować instancji ClassToSerialize $ MyEnum z wartości ciągu „stringValue”: wartość nie jest jedną z zadeklarowanych nazw instancji Enum: [FIRST, SECOND, THIRD]

Ale po dodaniu @JsonPropertyadnotacji do konstruktora:

@JsonCreator
public ClassToSerialize(@JsonProperty("myEnum") MyEnum myEnum) {
    this.myEnum = myEnum;
}

Deserializacja powiodła się:

Serialized: {„myEnum”: „FIRST”, „stringValue”: „ABCD”}

StringValue: ABCD

MyEnum: FIRST

DVarga
źródło
2

Oprócz wszystkich powyższych odpowiedzi nie zapomnij o części dokumentacji, która mówi

Adnotacja znacznika, której można użyć do zdefiniowania metody niestatycznej jako „ustawiającej” lub „pobierającej” dla właściwości logicznej (w zależności od jej podpisu) lub niestatycznego pola obiektowego, które ma być używane (szeregowane, deserializowane) jako logiczne własność.

Jeśli masz non-staticw swojej klasie metodę, która nie jest konwencjonalna getter or setter, możesz sprawić, by działała jak getter and setterza pomocą adnotacji na niej. Zobacz przykład poniżej

public class Testing {
    private Integer id;
    private String username;

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getIdAndUsername() {
        return id + "." + username; 
    }

    public String concatenateIdAndUsername() {
        return id + "." + username; 
    }
}

Kiedy powyższy obiekt jest szeregowany, odpowiedź będzie zawierać

  • nazwa użytkownika od getUsername()
  • ID z getId()
  • idAndUsername od getIdAndUsername*

Ponieważ metoda getIdAndUsernamezaczyna się od gettego momentu, jest traktowana jako normalny getter, dlatego też można przypisać takie adnotacje @JsonIgnore.

Jeśli zauważyłeś, że concatenateIdAndUsernamenie jest zwracany, a to dlatego, że jego nazwa nie zaczyna się od, geta jeśli chcesz, aby wynik tej metody został uwzględniony w odpowiedzi, możesz go użyć @JsonProperty("...")i będzie traktowany jak normalnie, getter/setterjak wspomniano w powyższej wyróżnionej dokumentacji .

Raf
źródło
0

Z JsonProperty javadoc,

Definiuje nazwę właściwości logicznej, tj. Nazwę pola obiektu JSON do użycia dla tej właściwości. Jeśli wartość jest pusta Łańcuch (który jest wartością domyślną), spróbuje użyć nazwy pola z adnotacjami.

sc30
źródło