JSR Bigdecimal Validation is not working with #Digits - spring

Hi I am trying to validate integer and precision part for one column. Its not validating at all against Bigdecimal value. My Database is Oracle. Its validating if i am changing the data type to String .
#Column(name = "L_MI_COVERAGE_PERCENT")
#Digits(integer=3, fraction=6, message = "MI Coverage Percent should be precision 9 and scale 6.")
private BigDecimal miCoveragePercent;
My database Column is
L_MI_COVERAGE_PERCENT NUMBER(9,6)
I am passing a value like this 100001.10 . When i am running the application i am getting error as
org.hibernate.exception.DataException: could not execute statement .
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Loans>> violations =
validator.validate(loans);
I am not getting any violations , but other fields validations are happening and messages are coming back in violations object except miCoveragePercent. This is the only with Bigdecimal.

Related

How to save list of items into database when we have UUID in spring boot jpa

We have a requirement where 3k to 4k records we need to save into database. User will add multiple items or select all to add to his watchlist after applying filter. I tried savellAndFlush(list) this is taking list of objects but while saving only one record is getting saved into database.
We are using Spring boot and JPA repository
Domain:
#Id    
#GeneratedValue(generator = "system-uuid")   
#GenericGenerator(name = "system-uuid", strategy = "org.hibernate.id.UUIDGenerator")    
#Column(name = "PK_WISHLIST_ID", unique = true, nullable = false, precision = 30, scale = 0)    
private String pkWishListId;
List<WatchList> watchList = new ArrayList<WatchList>();
watchListRepo.saveAllAndFlush(watchList);
This is executing without any issues but in database its not inserting all records, instead inserting only one record.

#PathVariable of GetMapping in Spring throws an error when the input is #

I have made an autosuggest input field that automatically searches the database on every keypress. It works fine when i insert regular characters like letters and numbers but it gets spooky when you try start the search request with the character #. Doing that throws the error org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'long'; nested exception is java.lang.NumberFormatException: For input string: "get"
When i add some letters before the # (for example des#) it will throw an 404 page not found error and if i use the % character it will throw an 400 'unauthorized' error.
This strange behavior has probably something to do that i'm expecting a GetRequest instead of a PostRequest. If i turn it into a PostMapping i'm sure the errors will dissapear. But my question is; why is this happening? Does # have a special meaning? Why does spring seemingly try to convert # to a long value even though the pathvariable is typed as String? And why has the input string become "get" according to the error? I know that in an url # has a special meaning in that it signifies an href anchor but why should it be a special character for spring?
Heres the code of my getMapping
#GetMapping("/get/varietynames/{searchString}/{languageCode}")
public List<CropVarietyNameSelectionDTO> getCropVarietySelectionDTOBySearchString(#PathVariable("searchString") #NotBlank #Pattern(regexp = "^[A-Za-z0-9]+$", message = "Search input only allows for letters and numbers")
#Size(min = 1, max = 40, message = "Search input cannot exceed 40 characters") String searchString, #PathVariable("languageCode") String languageCode){
return seedService.getCropVarietySelectionDTOBySearchString(searchString,languageCode);
}
Edit
Request on the frontend side is:
private basePath:string = this.apiUrl + "/seed";
getCropVarietySelectionDTOBySearchString(searchString: string):Observable<CropVarietyNameSelectionDTO[]>{
return (searchString && (searchString.trim().length > 0)) ? this.http.post<CropVarietyNameSelectionDTO[]>(this.basePath + "/get/varietynames/" + this.languageService.getCodeOfPreferredLanguage(), searchString) : Observable.of([]);
}
this.apiUrl = localhost:4200
That is not the correct way or option to use #PathVariable annotation which indicates that a method parameter should be bound to a URI template variable. You need to use #RequestParam annotation which indicates that a method parameter should be bound to a web request parameter. You can see this answer that is a #RequestParam vs #PathVariable
#GetMapping("/get/varietynames")
public List<CropXXXDTO> getXXXXXhString(#RequestParam #NotBlank
#Pattern(regexp = "^xx+$", message = "xxxxx")
#Size(min = 1, max = 40, message = "xxxxx") String searchString,
#RequestParam(required = false, defaultValue = "EN") String languageCode){
return seedService.getXXXXtring(searchString, languageCode);
}
Then you can check the URL by following way:
/get/varietynames?searchString=XXXXX&languageCode=EN

Bean validation - validate optional fields

Given a class that represents payload submitted from a form, I want to apply bean validation to a field that may or may not be present, for example:
class FormData {
#Pattern(...)
#Size(...)
#Whatever(...)
private String optionalField;
...
}
If optionalField is not sent in the payload, I don't want to apply any of the validators above, but if it is sent, I want to apply all of them. How can it be done?
Thanks.
So usually all of these constraints consider null value as valid. If your optional filed is null when it's not part of the payload all should work just fine as it is.
And for any mandatory fields you can put #NotNull on them.
EDIT
here's an example:
class FormData {
#Pattern(regexp = "\\d+")
#Size(min = 3, max = 3)
private final String optionalField;
#Pattern(regexp = "[a-z]+")
#Size(min = 3, max = 3)
#NotNull
private final String mandatoryField;
}
#Test
public void test() {
Validator validator = getValidator();
// optonal field is null so no violations will rise on it
FormData data = new FormData( null, "abc" );
Set<ConstraintViolation<FormData>> violations = validator.validate( data );
assertThat( violations ).isEmpty();
// optional field is present but it should fail the pattern validation:
data = new FormData( "aaa", "abc" );
violations = validator.validate( data );
assertThat( violations ).containsOnlyViolations(
violationOf( Pattern.class ).withProperty( "optionalField" )
);
}
You can see that in the first case you don't get any violations as the optional field is null. but in the second exmaple you receive a violation of pattern constraint as aaa is not a string of digits.

How to use arrays with Spring Data JDBC

I am trying to use Spring Data JDBC for my PostgreSQL database. I defined the following beans
#Data
class Report {
#Id
private Long id;
private String name;
private Set<Dimension> dimensions;
}
#Data
class Dimension {
private String name;
private Long[] filterIds;
}
and the corresponding DDL
CREATE TABLE report (
id bigserial PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE dimension (
id bigserial PRIMARY KEY ,
report bigint,
name text,
filter_ids bigint[],
FOREIGN KEY (report) REFERENCES report(id) ON DELETE CASCADE ON UPDATE CASCADE
);
Then I tried to insert a report
final Dimension dimension = new Dimension();
dimension.setName("xyz");
dimension.setFilterIds(new Long[]{ 1L, 2L, 3L });
final Report report = new Report();
report.setName("xyz");
report.setDimensions(Collections.singleton(dimension));
repository.save(report);
where repository is simply a CrudRepository<Report, Long>.
This gave me the following error
org.postgresql.util.PSQLException: ERROR: column "filter_ids" is of type bigint[] but expression is of type bigint
Hinweis: You will need to rewrite or cast the expression.
Position: 116
Can I somehow tell Spring Data JDBC how to map the array types?
With the release of Spring Data JDBC 1.1.0, this became possible. See the documentation here:
The properties of the following types are currently supported:
All primitive types and their boxed types (int, float, Integer, Float, and so on)
Enums get mapped to their name.
String
java.util.Date, java.time.LocalDate, java.time.LocalDateTime, and java.time.LocalTime
Arrays and Collections of the types mentioned above can be mapped to columns of array type if your database supports that.
...
As P44T answered this should work from version of 1.1 of Spring Data JDBC onwards just as you used it.
Original answer
It is currently not possible. There are issues for this. A starting point is this one: https://jira.spring.io/browse/DATAJDBC-259

Grails NumberFormatException or GroovyCastException with fields, that cause it

I'm throwing exceptions in services (especially these validation ones) and try-catch them in controllers. I'm getting data to
in firmController:
try{
def data = request.JSON
firmService.createAndSave(data)
}
catch(ValidationException exception){
}
in firmService:
def createAndSave(data){
firm.year = data.year as BigDecimal
firm.price = data.price as Float
firm.employees = data.employees as Integer
firm.name = data.name
if(!firm.validate()){
throw new ValidationException(null, firm.errors)
}
firm.save(flush:true)
firm
}
but if I send JSON with invalid data: {year:"asd", price: "fgh", employees: "3", name: "zxc"} I got an NumberFormatException. I know, I can catch NumberFormatException (or some kind of my own exception) in controller but how can I get a fields/properties for which it were thrown (and still throw it as an exception)?
With the current approach that you are using to initialize your domain object you can't. The NFE is being thrown when grails tries to cast String value asd as BigDecimal (data.year as BigDecimal) and it has nothing to do with ValidationException.
JSONObject class implements Map and in grails all Domains have a constructor that accepts a Map and can initialize the object using map properties. So instead of binding each property manually you can directly instantiate the object using new Firm(data) in firmService. In this way you will get a binding exception when grails will try to bind a non decimal value to a BigDecimal type field.

Resources