Reckless
Reckless

Reputation: 134

SpringBoot automatically converts integer to boolean with @RequestBody annotation? How can I reject the integer?

My request was an application/json type like this: {"able": true}, but when I send the request like this {"able":12345}, the field able still can get a correct value true. Why?

@PatchMapping("/{id}/path/{name}")
public ResponseEntity someMethod(
    @Valid @RequestBody SomeRequest request) {
    // do something
}

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SomeRequest {
    @AssertTrue
    @NotNull
    private Boolean able;
}

Upvotes: 3

Views: 6601

Answers (6)

kellyfj
kellyfj

Reputation: 6943

Another solution is to use Jackson's Coercion Configuration

https://cowtowncoder.medium.com/jackson-2-12-most-wanted-4-5-cbc91c00bcd2

Upvotes: 0

Khan
Khan

Reputation: 21

create a Custom BooleanDeserializer by extending the JsonDeserializer from jackson library,

public class BooleanValueDeserializer extends JsonDeserializer<Boolean> {

@Override
public Boolean deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JacksonException {
    try {
        return jsonParser.getBooleanValue();
    }catch(JsonParseException exception) {
        throw new RuntimeException(String.format("%s is not a valid Boolean value for %s", jsonParser.getText(), jsonParser.getCurrentName()));
    }
}
}

and add the following annotation on the Request Object for Deserialization

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SomeRequest {
    @NotNull
    @JsonDeserialize(using = BooleanValueDeserializer.class)
    private Boolean able;
}

Upvotes: 2

Reckless
Reckless

Reputation: 134

Actually the answer posted by sunsunsun is exactly. It works well. But my answer is re-code the setter method of SomeRequest like this:

    public void setAble(Object value) {
        if (value instanceof Boolean) {
            submitted = (Boolean) value;
        }
        if ("true".equals(value)) {
            submitted = true;
        }
    }

Because Jackson is using the setter method to inject value.

And then I can just accept the value which is true or "true". And I don't want to affect others.

Upvotes: 2

sunsunsun
sunsunsun

Reputation: 56

Because jackson.databind will parse int to bool when field type is bool. Find code in NumberDeserializers.BooleanDeserializer

            JsonToken t = p.getCurrentToken();
            if (t == JsonToken.VALUE_TRUE) {
                return Boolean.TRUE;
            }
            if (t == JsonToken.VALUE_FALSE) {
                return Boolean.FALSE;
            }
            return _parseBoolean(p, ctxt);

_parseBoolean(p, ctxt) will parse int to bool.

We can do it by ourselves not use default.

  1. Create our bool deser class.
public class MyDeser extends JsonDeserializer {
    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonToken t = p.getCurrentToken();
        if (t == JsonToken.VALUE_TRUE) {
            return Boolean.TRUE;
        }
        if (t == JsonToken.VALUE_FALSE) {
            return Boolean.FALSE;
        }
        return null; 
        // not parse int to bool but null and it may work ok.
        // if throw new IOException(), it will work fail. Maybe return null means use other deser to deal it. throw Exception means fail. I don't know it clearly.
    }
}
  1. Create a configuration and inject a SimpleModule bean. I write in application
 @SpringBootApplication
 @Configuration
 public class DemoApplication {
     @Bean
     public SimpleModule addDeser() {
         return new SimpleModule().addDeserializer(Boolean.class, new MyDeser());
     }
     public static void main(String[] args) {
         SpringApplication.run(DemoApplication.class, args);
     }
 }

Upvotes: 4

Taran
Taran

Reputation: 27

Each non zero value will be treated as true in boolean case. If you send zero then it will set value to false.

Upvotes: 0

Cayman
Cayman

Reputation: 387

Maybe because each non-zero integer value is true? What happens if you sent {"able":0} ?

Upvotes: 0

Related Questions