Hibernate Validator validate set - java

I have custom validation annotation called #Role and I have custom validator which validates User and it works. Problem is when I want to use this validator on Set<User> to validate every element on this set like this
public class Project {
// Validates
#Role
private User creator;
// Throws error
#Role
private Set<User> users;
}
This sadly throws this error:
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'cz.studenthub.validators.annotations.Role' validating type 'java.util.Set<cz.studenthub.core.User>'
Is there any way to validate collections without having to write new validator for Set<User>?
Note: I don't want to use #Valid for User because that instance doesn't need to be completely valid, it just needs to meet that one condition validated by my RoleValidator.

I would suggest you to use Hibernate Validator 6.0.0.Beta2 if you can.
We now have support for container element constraints so you can simply do:
public class Project {
// Validates
#Role
private User creator;
private Set<#Role User> users;
}
We are planning a Candidate Release 1 in a week so it's already pretty stable.

Related

How to hardcode group information on field for cascading validation

I have the following bean;
public class Customer {
#NotNull(groups = New.class)
private String id;
#Valid
private List<CustomerDetail> detailList;
}
As you see, I cascade validation down to each CustomerDetail in detailList by annotating the field with #Valid, but I wish to propagate the validation with a hard-coded group, is that possible? Whatever group is supplied for validation, I wish a fixed group, namely New to be active in validation of detailList.
This is due to my conflicting requirements, one wishes to treat details as a sub-resource of Customer therefore I need full validation on it all the time when it is validated within a customer pojo. Another requirement is to treat each detail as a separate resource, therefore I need to do patch for some fields, so when it is validated separately, different groups can be applied.
public class CustomerDetail {
#NotNull(groups = New.class)
private String desc;
private String remark;
}
So when it is any sort of operation for Customer, every CustomerDetail in customerList should use New group, even if Customer does not necessarily use that group for validation.
In a way, I want to do this;
public class Customer {
#NotNull(groups = New.class)
private String id;
#Validated(New.class)
private List<CustomerDetail> detailList;
}
But I was unable to find such a feature, I wanted to do this to evade creating multiple groups, which was deemed confusing.
You need to introduce your own annotation to have class level constraints. Create a custom annotation with own validation logic implemented in the validator.
See the chapter 6.2. Class-level constraints of the doc
Or see the example

Hibernate + Spring: Conditional on create bean validation

I use the date validaton using the #Future annotation.
#NotNull
#DateTimeFormat(pattern="yyyy-MM-dd")
#Column(name = "FROM")
#Temporal(TemporalType.DATE)
#Future
private Date from;
#NotNull
#Column(name = "FOO")
private String foo;
I perform CRUD operations using Rest API. The requirement is the from date will be in future - after the entity is being created (today). However, the time changes and in case of changing the field foo using ex. PUT method, the validation won't pass.
#PutMapping(value = "/{id}")
public ResponseEntity<?> put(
#Valid #RequestBody MyEntity myEntity,
#PathVariable("id") int id)
{
... update entity based on id
}
When I call this method in the far future (after the from value persisted), the validation doesn't let me perform the operation, because the field from is no more valid.
There is a simple in-built solution to trigger a certain validation only on create event?
I have been thinking over creating the own cross-field validation through annotation, however I am not able to determine the creation based on other fields.
You can use Grouping Constraints, to restrict which validation set to use for: pre-persist, pre-update, pre-remove and ddl(For database schema).
So to validate from field just for persist operation and ignore it for put(update), you may:
Add an interface e.g. GroupFuture:
package com.example.entity;
public interface GroupFuture {}
In your MyEntity, I think you should also add #NotNull constraint as #Future consider null as valid value:
//...
//Maybe #NotNull
#Future(groups = GroupFuture.class)
private Date from;
//...
Finally, if you've configured hibernate using:
persistence.xml, add this line in the persistence-unit setting:
<property name="javax.persistence.validation.group.pre-persist" value="javax.validation.groups.Default, com.example.GroupFuture">
Programmatically:
// If you're using pure hibernate
Configuration configuration = new Configuration().setProperty("javax.persistence.validation.group.pre-persist", javax.validation.groups.Default, com.example.GroupFuture);
`
// If you're using JPA/hibernate
entityManagerFactory.getJpaPropertyMap().put("javax.persistence.validation.group.pre-persist", javax.validation.groups.Default, com.example.GroupFuture);
Useful reading(even it's for hibernate 3.6): Chapter 23. Additional modules

Multiple constraints spring validation

I am using spring to validate a form. The model for the form is similar to this:
public class FormModel {
#NotBlank
private String name;
#NotNull
#ImageSizeConstraint
private MultipartFile image;
}
The '#ImageSizeConstraint' is a custom constraint. What I want is for the #NotNull to be evaluated first and if this evaluates to false, not to evaluate #ImageSizeConstraint.
If this is not possible, I will have to check for null in the custom constraint as well. Which is not a problem, but I would like to seperate the concerns (not null / image size / image / aspectratio / etc).
You may use constraints grouping and group sequences to define the validation order. According to JSR-303 (part 3.5. Validation routine):
Unless ordered by group sequences, groups can be validated in no
particular order. This implies that the validation routine can be run
for several groups in the same pass.
As Hibernate Validator documentation says:
In order to implement such a validation order you just need to define
an interface and annotate it with #GroupSequence, defining the order
in which the groups have to be validated (see Defining a group
sequence). If at least one constraint fails in a sequenced group, none
of the constraints of the following groups in the sequence get
validated.
First, you have to define constraint groups and apply them to the constraints:
public interface CheckItFirst {}
public interface ThenCheckIt {}
public class FormModel {
#NotBlank
private String name;
#NotNull(groups = CheckItFirst.class)
#ImageSizeConstraint(groups = ThenCheckIt.class)
private MultipartFile image;
}
And then, as constraints are evaluated in no particular order, regardless of which groups they belong to (Default group too), you have to create #GroupSequence for your image field constraints groups.
#GroupSequence({ CheckItFirst.class, ThenCheckIt.class })
public interface OrderedChecks {}
You can test it with
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<FormModel>> constraintViolations =
validator.validate(formModel, OrderedChecks.class);
To apply this validation in Spring MVC Controller methods, you may use the #Validated annotation, which can specify the validation groups for method-level validation:
#PostMapping(value = "/processFormModel")
public String processFormModel(#Validated(OrderedChecks.class) FormModel formModel) {
<...>
}
Easy just return true for isValid if image is null for your custom constraint.
Read the specification of JSR-303, you will see that this is normal behaviour and it makes sense as there is "NotNull".

No property findAllEntries found for type Entry

I don't know why Spring doesn't like my code:
I have Entry.java:
#Entity
#Table(name = "entries")
public class Entry {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "text")
private String text;
}
EntryDao.java:
public interface EntryDao extends JpaRepository<Entry, Long> {
List<Entry> findAllEntries();
}
EntryService.java:
#Service
public interface EntryService {
List<Entry> findAllEntries();
}
EntryServiceImpl.java:
public class EntryServiceImpl implements EntryService {
private EntryDao entryDao;
private SessionFactory sessionFactory;
#Override
#SuppressWarnings("unchecked")
public List<Entry> findAllEntries() {
Session session = this.sessionFactory.getCurrentSession();
List<Entry> entries = session.createQuery("from entries").list();
return entries;
}
}
This code gives me an error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entryDao': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property findAllEntries found for type Entry!
I don't understand how to handle this error and why this error occurs.
The root cause you got the exception is that you're against the convention/rules to declare/create queries in Spring Data JPA.
The official docs of Spring Data JPA mentioned that:
The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.
The central interface of abstraction is Repository, to manage your entity, you need to declare your own interface of Repository and JPA will help you to create proxy instances for those interfaces. There're already some base Repositories like CrudRepository or PagingAndSortingRepository to provide basic functionalities as you can tell from their names, so by extending those basic ones, you'll have many basic methods. To define more specific access methods, you need to follow the ways JPA provided to create queries:
Define method in your interface following the method name convention
Use #Query annotation to define it manually
For the first method, the docs of Query Create has detailed clarification, here's some key idea:
The mechanism strips the prefixes find…By, read…By, query…By, count…By, and get…By from the method and starts parsing the rest of it. The introducing clause can contain further expressions such as a Distinct to set a distinct flag on the query to be created. However, the first By acts as delimiter to indicate the start of the actual criteria. At a very basic level you can define conditions on entity properties and concatenate them with And and Or
Simply speaking, JPA will parse the method name and try to find the related property to create query criteria for you.
Now let's have a look at your code, if you just want to retrieve all of your entities, you don't need to define your own method, there's already findAll methods pre-defined, if you want to retrieve entities based on text content, it's supposed to look like:
Entity findByText(String text)
but your method findAllEntites just don't match any rules, so JPA throws such an error message to you.
As #AbdullahWasi said, just use the existing findAll() method from SpringData for your code. You might want to place a #Transactional annotation in your code, but that depends on your transaction boundaries.
Just remove your custom method from your Dao.
public interface EntryDao extends JpaRepository<Entry, Long> {
}
And use the default spring data findAll
#Transactional
public class EntryServiceImpl implements EntryService {
private EntryDao entryDao;
private SessionFactory sessionFactory;
#Override
#SuppressWarnings("unchecked")
public List<Entry> findAllEntries() {
return entryDao.findAll();
}
}

JSR-303 How to validate two children objects differently

I'm using Hibernate Validator as JSR-303 implementation.
Suppose I have:
class Form {
#Valid
private Owner mainOwner;
#Valid
private Owner secondOwner;
// ... many other fields
}
class Owner {
#DriverLicenseValid // some custom validation
private String driverLicense;
// ... many other fields
}
// ...
Form myForm;
validator.validate(myForm);
See, I want to validate the whole form, it contains two similar child objects of type Owner. Problem is that for mainOwner driverLicense should be #NotNull while for secondOwner it should be #Null.
I can't use groups here (can I?) since the whole model is checked by a single validate() call. Is there any way to solve this without writing this rule as a custom constraint on the Form level?
Create a validation annotation on the mainOwner field in Form that validates that the Owner instance has a set driver license.
The #DriverLicenseValid annotation should just follow the suggestions from the jsr-303 spec that null values are valid by default. So you don't need to change the Owner class.
If you work with Hibernate Validator 4.x, you could use a custom group sequence provider as described in this forum post.
Use groups:
class Form {
#Valid
#ConvertGroup(from=Default.class, to=NotNullDriversLicense.class)
private Owner mainOwner;
#Valid
#ConvertGroup(from=Default.class, to=NullDriversLicense.class)
private Owner secondOwner;
// ... many other fields
}
class Owner {
#Null(groups = NullDriversLicense.class)
#NotNull(groups = NotNullDriversLicense.class)
private String driverLicense;
// ... many other fields
}
interface NullDriversLicense {}
interface NotNullDriversLicense {}
// ...
Form myForm;
validator.validate(myForm);

Categories