Jackson: Is there a way to ignore 0/1 on Boolean deserialization?

依然范特西╮ 提交于 2021-02-05 05:52:08

问题


I have a JSON object with a Boolean property that needs to allow only true or false during the deserialization.

Any value different of true and false should throw an exception.

How can I do that?


e.g.:

Valid json:

{
  "id":1,
  "isValid":true
}

Invalid json:

{
  "id":1,
  "isValid":1
}

Update

I tried what @Michał Ziober proposed and it worked fine.

As I'm implementing a Spring application (with Webflux) I just had to configure in a different way. I'm posting here what I did:

  • Create a Configuration class extending from DelegatingWebFluxConfiguration
  • Override the configureHttpMessageCodecs method setting the property on ObjectMapper
@Configuration
public class JacksonConfig extends DelegatingWebFluxConfiguration {

    @Override
    protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        configurer.defaultCodecs()
                .jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper));
    }
}

回答1:


You need to disable ALLOW_COERCION_OF_SCALARS feature:

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS);

        System.out.println(mapper.readValue(jsonFile, Pojo.class));
    }
}

class Pojo {

    private int id;
    private Boolean isValid;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Boolean getIsValid() {
        return isValid;
    }

    public void setIsValid(Boolean valid) {
        isValid = valid;
    }

    @Override
    public String toString() {
        return "Pojo{" +
                "id=" + id +
                ", isValid=" + isValid +
                '}';
    }
}

Above code prints:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot coerce Number (1) for type java.lang.Boolean (enable MapperFeature.ALLOW_COERCION_OF_SCALARS to allow) at [Source: (File); line: 3, column: 14] (through reference chain: Pojo["isValid"]) at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)




回答2:


Well, it's not a for-any-case implementation, but may be it'll be suitable for you:

public class TestBooleanDeserializer extends JsonDeserializer<Boolean> {

  @Override
  public Boolean deserialize(JsonParser jsonParser, DeserializationContext context)
      throws IOException, JsonProcessingException {
    String str = jsonParser.getText();    
    boolean val = Boolean.valueOf(str);
    if (!val && Objects.nonNull(str) && !Objects.equals("false", str.toLowerCase())) {
      throw new RuntimeException("invalid JSON");
    }
    return val;
  }

}

Since a Boolean.valueOf is a result of check of the java.lang.Boolean#

public static boolean parseBoolean(String s) {
    return ((s != null) && s.equalsIgnoreCase("true"));
}

here: boolean val = Boolean.valueOf(str); you'll check is it a true value or not. If not, you should check is it null or false: if (!val && Objects.nonNull(str) && !Objects.equals("false", str.toLowerCase())) if it's not you can throw an exception whatever you need. Otherwise you'll return a boolean value



来源:https://stackoverflow.com/questions/57778322/jackson-is-there-a-way-to-ignore-0-1-on-boolean-deserialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!