Когда используется свойство @JsonProperty и для чего оно используется?

183

Этот боб 'State':

public class State {

    private boolean isSet;

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

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

}

отправляется по сети с помощью обратного вызова ajax 'success':

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

Здесь требуется аннотация @JsonProperty? В чем преимущество его использования? Я думаю, что могу удалить эту аннотацию, не вызывая побочных эффектов.

Читая об этом аннексе по адресу https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations Я не знаю, когда это необходимо использовать?

голубое небо
источник

Ответы:

238

Вот хороший пример. Я использую его для переименования переменной, потому что JSON исходит из .Netсреды, в которой свойства начинаются с заглавной буквы.

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

Это правильно анализирует в / из JSON:

"Parameter":{
  "Name":"Parameter-Name",
  "Value":"Parameter-Value"
}
OldCurmudgeon
источник
1
Могут ли переменные-члены String не быть переименованы в их правильный регистр, поэтому public String name; становится публичным String Name; ?
голубое небо
14
Да, они могут, но в среде Java, которая делает их не соответствующими стандартам кодирования. Это больше касается моей педантичности, что реальная проблема кодирования, но это хороший, но простой пример реального использования @JsonPropertyаннотации.
OldCurmudgeon
Можно ли использовать эту аннотацию для члена типа Double? Мне просто интересно, должен ли тип быть Stringили какой-либо тип, который поддерживает JSON? Может ли это быть какой-нибудь тип? @OldCurmudgeon
Dreamer
3
@ Мечтатель Да. Тип не имеет значения. Это влияет только на имя .
OldCurmudgeon
1
@ Паван - Это не имеет ничего общего с именами. Я предполагаю, что вы должны проверить свои сеттеры.
OldCurmudgeon
44

Я думаю, что OldCurmudgeon и StaxMan оба верны, но вот одно предложение с простым примером для вас.

@JsonProperty (name), сообщает Jackson ObjectMapper сопоставить имя свойства JSON с именем аннотированного поля Java.

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

//where it gets mapped 
public static class Car {
  @JsonProperty("Type")
  public String type;
 }
grepit
источник
Имя класса должно совпадать с корневым элементом JSON. Это не работает для меня.
Паван
39

хорошо для того, что это стоит сейчас ... JsonProperty также используется для определения методов получения и установки для переменной помимо обычной сериализации и десериализации. Например, предположим, что у вас есть полезная нагрузка, подобная этой:

{
  "check": true
}

и класс десериализатора:

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

Тогда в этом случае аннотация JsonProperty необходима. Однако, если у вас также есть метод в классе

public class Check {

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

  public Boolean getCheck() {
     return check;
  }
}

Ознакомьтесь также с этой документацией: http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonProperty.html.

Richeek
источник
15

Без аннотаций выведенное имя свойства (для сопоставления с JSON) будет «задано», а не - как кажется, намерение - «isSet». Это связано с тем, что согласно спецификации Java Beans методы формы "isXxx" и "setXxx" означают, что существует логическое свойство "xxx" для управления.

StaxMan
источник
1
Это правильный ответ для конкретного случая, приведенного в вопросе
Эндрю Спенсер
6

Как вы знаете, это все о сериализации и опреснении объекта. Предположим, есть объект:

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

Сериализация этого объекта:

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

Имя переменной напрямую используется для сериализации данных. Если вы собираетесь удалить системный API из системной реализации, в некоторых случаях вам придется переименовать переменную в сериализации / десериализации. @JsonProperty - это метаданные, чтобы сообщить сериализатору, как выполнять последовательный объект. Он используется для:

  • имя переменной
  • доступ (ЧИТАТЬ, НАПИСАТЬ)
  • значение по умолчанию
  • требуется / опционально

из примера:

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; 
}
Мостафа
источник
6

Добавление JsonProperty также обеспечивает безопасность в случае, если кто-то решит, что он хочет изменить одно из имен свойств, не осознавая, что рассматриваемый класс будет сериализован в объект Json. Если они меняют имя свойства, JsonProperty гарантирует, что оно будет использоваться в объекте Json, а не имя свойства.

arush436
источник
3

В дополнение к другим ответам, @JsonPropertyаннотация действительно важна, если вы используете @JsonCreatorаннотацию в классах, которые не имеют конструктора без аргументов.

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

В этом примере единственный конструктор помечен как @JsonCreator, поэтому Джексон будет использовать этот конструктор для создания экземпляра. Но вывод выглядит так:

Сериализовано: {"stringValue": "ABCD", "myEnum": "FIRST"}

Исключение в потоке "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: Невозможно создать экземпляр ClassToSerialize $ MyEnum из строкового значения 'stringValue': значение не одно из объявленных имен экземпляров Enum: [FIRST, SECOND, THIRD]

Но после добавления @JsonPropertyаннотации в конструкторе:

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

Десериализация прошла успешно:

Сериализовано: {"myEnum": "FIRST", "stringValue": "ABCD"}

StringValue: ABCD

MyEnum: ПЕРВЫЙ

DVarga
источник
2

В дополнение ко всем ответам выше, не забывайте часть документации, которая говорит

Аннотация маркера, которая может использоваться для определения нестатического метода в качестве «установщика» или «получателя» для логического свойства (в зависимости от его сигнатуры) или поля нестатического объекта, которое будет использоваться (сериализовано, десериализовано) в качестве логического свойство.

Если non-staticв вашем классе есть метод, который не является традиционным, getter or setterвы можете заставить его действовать как a getter and setter, используя аннотацию к нему. Смотрите пример ниже

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

Когда вышеуказанный объект сериализуется, тогда ответ будет содержать

  • имя пользователя от getUsername()
  • идентификатор от getId()
  • idAndUsername от getIdAndUsername*

Так как метод getIdAndUsernameначинается с того, что getон рассматривается как обычный метод получения , поэтому вы можете аннотировать это с помощью @JsonIgnore.

Если вы заметили, что concatenateIdAndUsernameоно не возвращено, и это потому, что его имя не начинается с, getи если вы хотите, чтобы результат этого метода был включен в ответ, то вы можете использовать @JsonProperty("...")его, и он будет рассматриваться как обычный, getter/setterкак упомянуто в выделенной выше документации ,

Raf
источник
0

От JsonProperty Javadoc,

Определяет имя логического свойства, то есть имя поля объекта JSON, которое будет использоваться для свойства. Если значение является пустым String (который является значением по умолчанию), попытается использовать имя поля, которое аннотируется.

SC30
источник