Как я могу сериализовать / де-сериализовать логическое значение из FasterXML \ Jackson как Int?

Я пишу клиент JSON для сервера, который возвращает логические значения как «0» и «1». Когда я пытаюсь запустить свой JSON-клиент, я получаю следующее исключение:

HttpMessageNotReadableException: Could not read JSON: Can not construct instance of java.lang.Boolean from String value '0': only "true" or "false" recognized

Итак, как я могу настроить FasterXML \ Jackson для правильного анализа чего-то вроде:

{
   "SomeServerType" : {
     "ID" : "12345",
     "ThisIsABoolean" : "0",
     "ThisIsABooleanToo" : "1"
   }
}

Образцы Pojo:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"someServerType"})
public class myPojo
{
   @JsonProperty("someServerType")
   SomeServerType someServerType;

   @JsonProperty("someServerType")
   public SomeServerType getSomeServerType() { return someServerType; }

   @JsonProperty("someServertype")
   public void setSomeServerType(SomeServerType type)
   { someServerType = type; }
}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"someServerType"})
public class SomeServerType 
{
   @JsonProperty("ID")
   Integer ID;

   @JsonProperty("ThisIsABoolean")
   Boolean bool;

   @JsonProperty("ThisIsABooleanToo")
   Boolean boolToo;

   @JsonProperty("ID")
   public Integer getID() { return ID; }

   @JsonProperty("ID")
   public void setID(Integer id)
   { ID = id; }

   @JsonProperty("ThisIsABoolean")
   public Boolean getThisIsABoolean() { return bool; }

   @JsonProperty("ThisIsABoolean")
   public void setThisIsABoolean(Boolean b) { bool = b; }

   @JsonProperty("ThisIsABooleanToo")
   public Boolean getThisIsABooleanToo() { return boolToo; }

   @JsonProperty("ThisIsABooleanToo")
   public void setThisIsABooleanToo(Boolean b) { boolToo = b; }
}

Строка клиента отдыха
Примечание 1: Используется Spring 3.2
Примечание 2: toJSONString () - вспомогательный метод, который использует Джексона для сериализации моего объекта параметров
Примечание 3: Исключение происходит при чтении объекта результата

DocInfoResponse result = restTemplate.getForObject(docInfoURI.toString()
                                  + "/?input={input}",
                                  DocInfoResponse.class,
                                  toJSONString(params));

person Raystorm    schedule 15.12.2015    source источник
comment
Пожалуйста, добавьте соответствующий код вашего клиента.   -  person Alfabravo    schedule 15.12.2015
comment
Вы можете определить методы получения для тех значений, которые возвращают что-то вроде return "1".equals(stringRepresentation);.   -  person Titus    schedule 15.12.2015


Ответы (2)


Как упоминалось и упоминалось в ответе Пауло Педросо, вам нужно будет свернуть свои собственные JsonSerializer и JsonDeserializer. После создания вам нужно будет добавить аннотации @JsonSerialize и @JsonDeserialize к своему ресурсу; указание класса, который будет использоваться для каждого.

Ниже я привел небольшой (надеюсь, простой) пример. Ни сериализатор, ни десериализатор не являются сверхнадежными, но это должно помочь вам начать работу.

public static class SimplePojo {

    @JsonProperty
    @JsonSerialize(using=NumericBooleanSerializer.class)
    @JsonDeserialize(using=NumericBooleanDeserializer.class)
    Boolean bool;
}

public static class NumericBooleanSerializer extends JsonSerializer<Boolean> {

    @Override
    public void serialize(Boolean bool, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonProcessingException {
        generator.writeString(bool ? "1" : "0");
    }   
}

public static class NumericBooleanDeserializer extends JsonDeserializer<Boolean> {

    @Override
    public Boolean deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
        return !"0".equals(parser.getText());
    }       
}

@Test
public void readAndWrite() throws JsonParseException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();

    // read it
    SimplePojo sp = mapper.readValue("{\"bool\":\"0\"}", SimplePojo.class);
    assertThat(sp.bool, is(false));

    // write it
    StringWriter writer = new StringWriter();
    mapper.writeValue(writer, sp);
    assertThat(writer.toString(), is("{\"bool\":\"0\"}"));
}
person callmepills    schedule 12.02.2016
comment
На самом деле вам не нужен десериализатор: Джексон автоматически десериализует 0/1 в логическое свойство POJO без каких-либо аннотаций. И в моем случае мне тоже не понадобился сериализатор, поскольку сервер, который я вызываю, принимает и преобразует литералы true / false для этого поля. Я все равно вручаю награду. - person Andrew Spencer; 15.02.2016
comment
@AndrewSpencer Спасибо, я ценю награду. :) Чтобы было ясно, Джексон, кажется, автоматически десериализует свойство, если оно представлено как число, а не как строка. - person callmepills; 15.02.2016
comment
Не дай бог десериализуемый JSON не содержит поля, или оно есть, и значение пустое. Джексон выдаст упакованный NPE, который выглядит следующим образом: Ошибка преобразования объекта com.fasterxml.jackson.databind.JsonMappingException: (было java.lang.NullPointerException) - person snakedog; 09.12.2019

Вместо настраиваемого десериализатора вы также можете просто установить сеттер, например:

public void setThisIsABoolean(String str) {
  if ("0".equals(str)) {
    bool = false;
  } else {
    bool = true;
  }
}

поскольку ваш метод может претендовать на тип, отличный от того, который вы используете внутри.

И если вам нужно поддерживать как Boolean, так и String, вы можете указать значение Object и проверить, что вы можете получить.

Должна быть даже возможность иметь разные типы для метода получения (Boolean) и установщика (String или Object).

person StaxMan    schedule 12.02.2016
comment
Подходит для изменяемых объектов. Если наш POJO неизменяемый, мы не можем использовать этот метод. - person galcyurio; 23.05.2018
comment
@galcyurio Та же идея работает с @JsonCreator аннотированными конструкторами и фабричными методами, тоже чего стоит (или, что эквивалентно подходу Builder). - person StaxMan; 23.05.2018