Quando a propriedade @JsonProperty é usada e para que é usada?

183

Este bean 'State':

public class State {

    private boolean isSet;

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

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

}

é enviado pela conexão usando o retorno de chamada do ajax 'success':

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

A anotação @JsonProperty é necessária aqui? Qual é a vantagem de usá-lo? Eu acho que posso remover esta anotação sem causar efeitos colaterais.

Lendo sobre esta anotação em https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations Não sei quando isso é necessário para ser usado?

céu azul
fonte

Respostas:

238

Aqui está um bom exemplo. Eu o uso para renomear a variável porque o JSON é proveniente de um .Netambiente em que as propriedades começam com uma letra maiúscula.

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

Isso analisa corretamente de / para o JSON:

"Parameter":{
  "Name":"Parameter-Name",
  "Value":"Parameter-Value"
}
OldCurmudgeon
fonte
1
As variáveis ​​de membro String não podem ser renomeadas para o caso correto, portanto, público String name; torna-se público String Name; ?
blue-sky
14
Sim, eles podem, mas em um ambiente Java que os faz não corresponder aos padrões de codificação. É mais sobre o meu pedantismo um problema de codificação real, mas é um exemplo bom e simples de um uso real da @JsonPropertyanotação.
OldCurmudgeon
Esta anotação pode ser usada para o membro do tipo Double? Eu só estou querendo saber se o tipo tem que ser Stringou qualquer tipo que JSON suporte? Poderia ser qualquer tipo @OldCurmudgeon?
Dreamer
3
@Dreamer Sim. O tipo é irrelevante. Isso afeta apenas o nome .
25917 OldCurmudgeon
1
@Pavan - Isso não terá nada a ver com a nomeação. Eu acho que você deveria examinar seus levantadores.
OldCurmudgeon
44

Acho que OldCurmudgeon e StaxMan estão ambos corretos, mas aqui está uma resposta de sentença com um exemplo simples para você.

@JsonProperty (nome), informa ao Jackson ObjectMapper para mapear o nome da propriedade JSON para o nome do campo Java anotado.

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

//where it gets mapped 
public static class Car {
  @JsonProperty("Type")
  public String type;
 }
grepit
fonte
O nome da classe deve ser o mesmo que o elemento raiz do JSON. Isso não está funcionando para mim.
Pavan
39

bem para o que vale agora ... JsonProperty também é usado para especificar métodos getter e setter para a variável, além da serialização e desserialização usuais. Por exemplo, suponha que você tenha uma carga útil como esta:

{
  "check": true
}

e uma classe 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;
  }
}

Nesse caso, a anotação JsonProperty é necessária. No entanto, se você também tiver um método na classe

public class Check {

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

  public Boolean getCheck() {
     return check;
  }
}

Consulte também esta documentação: http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonProperty.html

Richeek
fonte
15

Sem anotações, o nome da propriedade inferida (para corresponder ao JSON) seria "definido" e não - como parece ser a intenção - "isSet". Isso ocorre porque, de acordo com a especificação do Java Beans, métodos dos formatos "isXxx" e "setXxx" são usados ​​para significar que há propriedade lógica "xxx" para gerenciar.

StaxMan
fonte
1
Esta é a resposta correta para o caso específico dado na questão
Andrew Spencer
6

Como você sabe, trata-se de serializar e dessalinizar um objeto. Suponha que exista um objeto:

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

A serialização deste objeto é:

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

O nome da variável é usado diretamente para serializar dados. Se você estiver prestes a remover a API do sistema da implementação do sistema, em alguns casos, precisará renomear a variável em serialização / desserialização. @JsonProperty é um metadado para informar ao serializador como objeto serial. É usado para:

  • nome variável
  • acesso (LER, ESCREVER)
  • valor padrão
  • obrigatório / opcional

do exemplo:

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
fonte
6

Adicionar o JsonProperty também garante segurança, caso alguém decida alterar um dos nomes de propriedades que não percebem que a classe em questão será serializada em um objeto Json. Se eles mudarem o nome da propriedade, o JsonProperty garantirá que será usado no objeto Json, e não o nome da propriedade.

arush436
fonte
3

Além de outras respostas, a @JsonPropertyanotação é realmente importante se você usar a @JsonCreatoranotação em classes que não possuem um construtor no-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);
    }
}

Neste exemplo, o único construtor é marcado como @JsonCreator, portanto, Jackson usará esse construtor para criar a instância. Mas a saída é como:

Serializado: {"stringValue": "ABCD", "myEnum": "PRIMEIRO"}

Exceção no encadeamento "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: Não é possível construir a instância de ClassToSerialize $ MyEnum a partir do valor da String 'stringValue': value não um dos nomes de instância declarados da Enum: [PRIMEIRO, SEGUNDO, TERCEIRO]

Mas após a adição da @JsonPropertyanotação no construtor:

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

A desserialização foi bem-sucedida:

Serializado: {"myEnum": "PRIMEIRO", "stringValue": "ABCD"}

StringValue: ABCD

MyEnum: FIRST

DVarga
fonte
2

Além de todas as respostas acima, não esqueça a parte da documentação que diz

Anotação de marcador que pode ser usada para definir um método não estático como "setter" ou "getter" para uma propriedade lógica (dependendo de sua assinatura) ou campo de objeto não estático a ser usado (serializado, desserializado) como um lógico propriedade.

Se você tem um non-staticmétodo em sua classe que não é convencional getter or setter, pode fazê-lo agir como um getter and setterusando a anotação nele. Veja o exemplo abaixo

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

Quando o objeto acima é serializado, a resposta conterá

  • nome de usuário de getUsername()
  • id de getId()
  • idAndUsername a partir de getIdAndUsername*

Como o método getIdAndUsernamecomeça get, é tratado como getter normal, portanto, por que você pode fazer anotações com @JsonIgnore.

Se você notou que o item concatenateIdAndUsernamenão é retornado e é porque o nome não começa gete se você deseja que o resultado desse método seja incluído na resposta, você pode usá @JsonProperty("...")-lo e ele será tratado como normal, getter/setterconforme mencionado na documentação destacada acima .

Raf
fonte
0

De JsonProperty javadoc,

Define o nome da propriedade lógica, ou seja, o nome do campo do objeto JSON a ser usado para a propriedade. Se o valor estiver vazio, String (que é o padrão), tentará usar o nome do campo anotado.

sc30
fonte