使用构建器时无法执行自定义反序列化

Unable to perform custom deserialisation when using a builder

我有一种情况,我从外部源接收到一个布尔值,作为字符串“0”或“1”。 映射时,杰克逊不接受这一点并抛出以下错误:

InvalidFormatException: Cannot deserialize value of type boolean from String "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 的 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.fasterxml.jackson.databind.JsonMappingException: Problem deserializing property 'bool' (expected type: [simple type, class java.lang.String]; actual type: java.lang.Boolean), problem: argument type mismatch at [Source: (String)"{"bool":"1"}"; line: 1, column: 9] (through reference chain: a.a.a.MyClass["bool"])

选项 2:

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

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

出现以下错误:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type boolean from String "1": only "true" or "false" recognized at [Source: (String)"{"bool":"1"}"; line: 1, column: 9] (through reference chain: a.a.a.MyClass$MyClassBuilder["bool"])

2020-11-03 更新:Lombok 1.18.16 发布。

从 Lombok 1.18.16 开始,您可以使用 @Jacksonized 自动生成 Jackson 使用 Lombok 所需的一切 @(Super)Builder:

@Getter
@Jacksonized
@Builder
public class MyClass {
    @JsonDeserialize(using = NumericBooleanDeserializer.class)
    private boolean bool;

    // many other fields
}

对于早期的 Lombok 版本,您必须自定义构建器,以便将注释添加到构建器的 setter 方法。在您的情况下,它的工作原理如下:

@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 识别出构建器已经有一个 class 定义,并且只为您没有手动实现的方法生成代码。