Невозможно выполнить пользовательскую десериализацию при использовании компоновщика - PullRequest
1 голос
/ 25 апреля 2020

У меня есть ситуация, когда я получаю логическое значение в виде строки «0» или «1» из внешнего источника. При отображении Джексон не принимает это и выдает следующую ошибку:

InvalidFormatException: Невозможно десериализовать значение типа boolean из строки «1»

Таким образом, я делает следующую пользовательскую десериализацию, которая работает.

Рабочий пример, когда выполняется без компоновщика

@Getter
public class MyClass {

    @JsonDeserialize(using = NumericBooleanDeserializer.class)
    @JsonProperty("bool")
    private boolean bool;

    // many other fields
}

class NumericBooleanDeserializer extends JsonDeserializer<Boolean> {

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

Но мне нужно это для работы со сборщиком и записи его следующим образом. Это больше не работает. Выдает ту же ошибку, что и выше. Есть ли способ обойти это для строителя, чтобы работать с пользовательской десериализацией? Обратите внимание, что я бы хотел использовать Lombok's Builder, если это вообще невозможно. Спасибо.

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

@Getter
@JsonDeserialize(builder = MyClass.MyClassBuilder.class)
@Builder
public class MyClass {

    @JsonDeserialize(using = NumericBooleanDeserializer.class)
    @JsonProperty("bool")
    private boolean bool;

    // many other fields
}

class NumericBooleanDeserializer extends JsonDeserializer<Boolean> {

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

Быстрый тестовый пример, чтобы проверить это, если хотите.

public class ATest {
    @Test
    public void myTest() throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        // test passes if MyClass doesn't use builder. 
        MyClass myClass = mapper.readValue("{\"bool\":\"1\"}", MyClass.class);
        assertTrue(myClass.isBool());
    }
}

РЕДАКТИРОВАТЬ: Попытка предложенных вариантов в соответствии с ответом ниже

Вариант 1:

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MyClass {

    @JsonDeserialize(using = NumericBooleanDeserializer.class)
    @JsonProperty("bool")
    private boolean bool;

    // many other fields

    @JsonSetter
    private void setBool(String value){
        this.bool = "1".equals(value);
    }
}

class NumericBooleanDeserializer extends JsonDeserializer<Boolean> {

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

Получение следующей ошибки:

com.faster xml .jackson.databind.JsonMappingException: проблема десериализации свойства 'bool' (ожидаемый тип: [простой тип, класс java .lang.String]; фактический тип: java.lang.Boolean), проблема: несоответствие типа аргумента at [Source: (String) "{" bool ":" 1 "}"; строка: 1, столбец: 9] (через цепочку ссылок: aaaMyClass ["bool"])

Опция 2:

@Getter
@JsonDeserialize(builder = MyClass.MyClassBuilder.class)
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MyClass {

    @JsonDeserialize(using = NumericBooleanDeserializer.class)
    @JsonProperty("bool")
    private boolean bool;
}

Получение следующей ошибки:

com.faster xml .jackson.databind.ex c .InvalidFormatException: Невозможно десериализовать значение типа boolean из строки "1": только "true" или "false" распознаются в [Source: ( Строка) "{" BOOL ":" 1 "}"; строка: 1, столбец: 9] (через цепочку ссылок: aaaMyClass $ MyClassBuilder ["bool"])

1 Ответ

1 голос
/ 25 апреля 2020

Самая последняя версия lombok, v1.18.12, копирует только @JsonProperty и @JsonSetter в методы установки разработчика. Это изменится со следующей версией, куда будут скопированы несколько других аннотаций Джексона, включая @JsonDeserialize; Я обновлю этот пост, когда он будет выпущен.

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

@Getter
@Builder
@JsonDeserialize(builder = MyClass.MyClassBuilder.class)
public class MyClass {
    private boolean bool;

    // many other fields

    public static class MyClassBuilder {
        @JsonDeserialize(using = NumericBooleanDeserializer.class)
        @JsonProperty("bool")
        public MyClassBuilder bool(boolean bool) {
            this.bool = bool;
            return this;
        }
    }
}

Lombok распознает, что уже существует определение класса для компоновщика, и генерирует код только для методов, которые вы не реализовали вручную.

...