Spring Boot validation takes float value in integer field - spring

I'm trying to implement a POST service with request validation.
My Controller method looks something like below
public void updateScore(#Valid ScoreRequest)
ScoreRequest looks like below
import javax.validation.constraints.*;
import lombok.Data;
#Data
public class ScoreRequest {
#Min(0)
#Max(100)
#Digits(fraction = 0, integer = 3)
private Integer score;
...
}
It all works fine till I pass integer values for score, however If I pass fraction part as well, request goes through and Spring somehow truncates the fraction and uses the integer part in the request.
I was expecting it to throw a validation error since datatype of score doesn't match.
It works with followling request, and uses 10 as the score value in the request object. I'm expecting it to throw an error, what am I doing wrong?
{"score": 10.234234}
Spring Boot version: 2.0.3.RELEASE

I was trying to debug Spring Boot's validation classes to find what was happening, but after looking at the comment by #M.Denium I searched for Jackson issues and found a related SO entry.
Java Jackson - prevent float to int conversion when deserializing
I'm using answer by #Jichao Zhang, however Just to confirm answer by #Eduardo Sanchez-Ros works as well. This is what works for me.
ObjectMapper.configure(DESERIALIZATION_FEATURE.ACCEPT_FLOAT_AS_INT, false);

Don't use this annotation: #Digits(fraction = 0, integer = 3 with Integer since it is useless to set fractions for Integer.
Why don't you do:
#Min(0)
#Max(100)
#Digits(fraction = 0, integer = 3)
private BigDecimal score;

If you closely look at the definition of the #digits annotation,
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
So this annotation can be applied to methods also.
If you read the docs, it says this annotation can be applied to the following types
BigDecimal
BigInteger
CharSequence
byte (or Byte)
short (or Short)
int (or Integer)
long (or Long)
the integer field of the annotation checks for the number of integral digits while the fraction field of the annotation checks for the number of fractional digits.
Since, you declared your field to be an Integer value. It casts the value to an integer and truncates the fractional part.
This does not fail validations as both the fields satisfy the validation.
This annotation is ideally to be only used with BigDecimal type.

Related

Exclude 0 from JSON response in Jackson Spring boot

I have a POJO like this.
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Test {
private int a;
private String b;
}
I want to exclude the property 'a' if it has 0 value. String b is excluded with
#JsonInclude(JsonInclude.Include.NON_NULL)
Only way I could thing of is convert the int data type to Integer Object and set the value to NULL in the setter explicitly if it is 0.
Any other suggestions or correct solution will be appreciated
Option 1:
Do what you said: Change int to Integer and use #JsonInclude(Include.NON_NULL). Because primitive types have default values and their values cannot be compared to null you have to wrap the int to Integer. See Primitive Data Types. imho this is the cleaner way.
Option 2:
Use the way described in this answer and use #JsonInclude(Include.NON_DEFAULT) instead (see Jackson-annotations API), so that default values (and so also null values for objects) will be ignored.
Note:
If you only want to exclude the specific field (in your case the int/Integer - a - field) when it has a null-/default value and the other fields (in your case the String - b - field) should be included when they have null-/default values, put the annotation on field level.

Validate at least 1 of a set of args is present in Kotlin class constructor

Scenario
I need to create a Kotlin class that can receive up to 4 arguments for its constructor, but only requires at least 1 out of a set of 3 (the fourth being entirely optional). To illustrate:
class Pie {
// Completely optional, the constructor should use it if present, otherwise it may be null.
var topping: String?
// Of these three [fillingA, fillingB, fillingC] 1 or more must be present.
var fillingA: String?
var fillingB: String?
var fillingC: String?
}
Thoughts
I've attempted to use Kotlin init{} blocks for validation, or telescoping constructors, but it gets ugly fast and I've yet to solve the issue. I have not found anything in the kotlinlang.org docs on primary/secondary constructors that is more elegant, though. My preference would be to find something similar to the #Size or #NotNull annotations, but I have failed to locate anything close.
It is important to note that I am using this class as a model for an API response.
Question
What is the most concise way to validate that a Kotlin class has at least 1 of a set of arguments passed to its constructor?
Are this fillings interchangeable? You could assume that fillingA is always required and the other ones are optional, something like this:
class Pie constructor(
val fillingA: String,
val fillingB: String? = null,
val fillingC: String? = null,
val topping: String? = null
){...}

how to detect missing primitive in request instead of defaulting the actual value to 0 in springboot?

I have a rest controller that receives a Json request which is wrapped in a DTO. In that DTO I have this field.
#NotNull(message = "value is mandatory.")
private double value;
The problem is that when I send a request missing this value, I dont get a validation error because maybe the value defaults to 0.
How can I make sure that I notify the caller if this value is actually missing in the payload and not default to 0 automatically in spring?
Used #M.Deinum's suggestion and it worked okay. Involves avoiding using primitives
#NotNull(message = "value is mandatory.")
private Double value;
I have a suggestion you can add one more annotation which helps you to avoid using zero like this
#Min(1)
#NotNull(message = "value is mandatory.")
private double value;
Now it will take min value 1 so maybe it will work

Spring MVC - Throws exception when the int value of ModelAttribute is null

I'm building an web application using Spring 3.0 MVC.
I have a method which has prototype below.
#RequestMapping(value = "/blahblah/blah.do", method=RequestMethod.GET)
public void searchData(#RequestParam(value="uniqOid", required=false) String uniqOid, #ModelAttribute("MasterVo") MasterVo searchVo,
ModelMap model, HttpServletResponse response, HttpServletRequest request)
The problem is that, the view (jsp) contains inputs that matches to searchVo(ModelAttribute).
When the int or long value of searchVo didn't come from the jsp, the server throws 404 page not found exception.
If the type of value is "String", it has no problem.
In my opinion, it is the problem of type casting.
How could I solve this problem, and which part of the server code that I have to check?
Thanks in advance.
I will go ahead and assume a few things about your problem.
It is not a type-cast problem. Spring has default converters that can easily convert from a String to some primitive type.
Now what you are facing is I think a null assigment to primitive type problem. Suppose the name of the property that's causing the problem is named primitiveProperty. Now, the request-paramters could include a parameter named primitiveProperty with an empty-String value, or some value that cannot be converted to a number. If the type of the primitiveProperty is String, it can assign the value of that parameter to it without any problem.
If the type of the primitiveProperty is int, long or some other primitive type that cannot have a null value, a problem occurs. When Spring converts the empty-string or a non-numeric string valued request-param named primitiveProperty, it cannot do so since that string can't be converted to a valid int or long value. So it is converted to null. Now, when Spring tries to assign that null value to a property that cannot have a null value (any primitve type), you get an Exception. If you are getting an empty-string as your request-param, you can replace the troublesome property in your domain object with its equivalent wrapper class (int with Integer, long with Long and so on). If you are getting a non-numeric value from your view, well, make sure that you don't get a non-numeric value.
You need to check the setter of the fields that are giving the typecast problem, in your case MasterVo .
The Spring will call the setter of the property to bind the value, where i presume you will see the error coming.
Just add a debug point to this setter and you will see the problem.

GroupSequence and order of evaluation in JSR 303

I have a field of type String in a command bean which has to be validated in the following order.
Must contain a value (not empty).
Must have exactly 6 characters.
Must confirm this regexp - [0-9, a-f, A-F]+
When any of them is violated, the rest must not be performed. I have tried to achieve this using #GroupSequence as follows.
#GroupSequence({TempBean.ValidationGroupNotEmpty.class, TempBean.ValidationGroupColourHexLength.class, TempBean.ValidationGroup.class, TempBean.class})
public final class TempBean
{
#NotEmpty(groups={ValidationGroupNotEmpty.class}, message="Must enter a valid colour code.")
#Length(min=6, max=6, groups={ValidationGroupColourHexLength.class}, message="Requires exactly 6 characters.")
#Pattern(groups={ValidationGroup.class}, regexp="[0-9, a-f, A-F]+", message="Invalid colour code.")
private String stringValue;
public interface ValidationGroup{}
public interface ValidationGroupNotEmpty{}
public interface ValidationGroupColourHexLength{}
// Getters and setters.
}
When the text-field is intentionally left blank, only #NotEmpty is performed but when I enter a value that violates the #Length and the #Pattern constraints, I'm getting both the messages as specified meaning they both are evaluated. This shouldn't happen. Only one of them should be performed at a time in the defined order. How can this be done?
I'm using Spring 3.2.0 and Hibernate Validator 4.3.1.
You code looks fine and I even tested it against HV 4.3.1. It works as expected. You are evaluating the Default group right? Have you tried to debug?

Resources