Disabling hibernate validation annotations dynamically at runtime? - java

Is it possible to turn off certain constraints / annotations per class at runtime? For instance if I wanted to turn of a #NotNull check on a firstName field, is that possible?
This would make testing to see whether a certain constraint is triggered correctly simpler, as I could turn off all the other constraints, and just check that one constraint.

Is it possible to turn off certain constraints / annotations per class
at runtime? For instance if I wanted to turn of a #NotNull check on a
firstName field, is that possible?
No it is not. Bean Validation does not define such a feature. There is an open issue in Hibernate Validator HV-98 which discusses the possibility of reloading metadata, but even there you would need to rebuild the validator factory.
You could override annotations via XML configuration and then recreate the Validator(Factory) instance using different configurations at the time, but that's probably not easy to mange.
This would make testing to see whether a certain constraint is
triggered correctly simpler, as I could turn off all the other
constraints, and just check that one constraint.
If it is about testing, you can use Validator.validateValue to just validate a given field. Other than that, if you validate the whole object graph and get a set of constraint violations back, you can just iterate over them and inspect the metadata. There is enough information in the metadata to verify that a specific constraints was executed and failed.

The hibernate validation annotation are usually used together with database constraints so it does not make sense to change the behavior at runtime. However if you want to do it you can implement your own validators (by overriding existing) and do whatever you want.

Related

What is the convenient schema update strategy to add #NotNull property to existing domain model in the context of hibernate?

I currently develop a small Java application with help of Spring Boot and Hibernate. As my application evolves, so does the domain model too. Last time I'm facing frequent updates of my domain model - new columns are added to existing tables. This new column addition happens not manually, but automatically via configured hibernate.ddl-auto=update property, as soon as I introduce new class variable (field) in my entity class.
The problems appear as soon as I add a new #NotNull annotation at the same time as I introduce new field, what is not surprising: old table entries could not have valid data in the new column without further action, therefore the whole update could result in corrupting database if it succeeds. Especially then, if hibernate first updates the table (by setting #NotNull constraint on the column), but then finds out that a lot of data in this column is invalid (null). Because of the hibernate.ddl-auto=update the corrupted column can not be restored with simple rollback of #NotNull property on the newly introduced field (i.e. if I comment this annotation out and start the application one more time). This is the reason why I am enforced to drop the whole table with the corrupted data in such situation, what is definitely not the way to do things properly, especially outside of the development environment.
Therefore my question: is there a way to update the existing domain model, such that the constraint #NotNull will not introduce such problems on newly created fields? What are the best practices for this sort of schema updates, especially if I want to avoid manually updating the whole database schema and want further rely on the hibernate schema creation?
If you want to set a default value for ALL rows you can set a default value with the #ColumnDefault annotation
If that's not fitting your requirements you might have just discovered one of the reasons why it's actually best practice NOT to rely on schema updater for production purposes at all, see official hibernate documentation - 26. Performance Tuning and Best Practices

How to validate both #PathVariable and #RequestBody in one ConstraintValidator in Spring?

I have an endpoint handler method in controller:
#PutMapping("/users/{userId}")
public UserDto updateUser(#PathVariable UUID userId, #RequestBody UserRequestDto updateRequest) {
...
}
Inside the UserRequestDto object I have an email field.
I would like to validate if the email value is not already in use.
It is not a problem for the creation as I only need to check if the email is not in the database. I've created a simple ConstraintValidator and everything is working.
But for the update, I need to check if the updated email address is not used by someone else and omit the currently update user. So I need to operate on both userId and updateRequest at once. Is it doable to create custom ConstraintValidator to handle this situation?
Since you posted code from a #RestController, I assume we are talking about validation at the controller level. I can share a few observations:
1) Note that you are trying to put business logic related validation into a ConstraintValidator. In your case it is validating fields from a data transfer object (i.e. UserRequestDto) that holds request attributes. At the controller level we should only be validating the request itself (i.e. "was all necessary information provided so I can actually start performing the operation?").
2) Because the understanding of "valid" will most likely differ from business use case to business use case, business logic related validation should go into a #Service bean where use case specific validation can be performed (such as "is there any other user with the same username or email?"). Most of the time this is done by manually checking different conditions, such as performing database queries or consulting other applications. At this level ConstraintValidators are counterproductive.
3) ConstraintValidators are most of the time used to perform a syntactical validation (i.e. "are all necessary values present in the expected format?") but not so much for semantical validation (i.e. "is the information correct according to the my business logic (which might involve database queries and consulting other applications)?").
So in your case, validating your UserRequestDto object using a custom ConstraintValidator is absolutely fine if you need to check whether all required attributes have been passed by the client in a specific format. However, checking if a username/email is already taken by another user should be performed by the logic layer in a use case specific manner - outside of a ConstraintValidator.
You can annotate your controller (class-level) with Spring's #Validated and then #NotBlank #PathVariable String something will work as well.
Spring will create an AOP proxy around all your methods and will look for JSR 303 annotations on every parameter but it will not touch #RequestBody, so for the body, you still must add #Valid which will be inspected by the standard means.
Also, see this issue https://github.com/spring-projects/spring-framework/issues/26219
Two approaches I could think of:
Approach 1:
Put a unique constraint on email id in your database schema. If you
try to save/update an already used email id, a constrain violation
exception will be thrown.
Approach 2:
While researching on the above topic I came across the link. You
can refer it once and see if your need is sufficed.
Maybe you can use Class-Level Constrains:
Last but not least, a constraint can also be placed on the class level. In this case not a single property is subject of the validation but the complete object. Class-level constraints are useful if the validation depends on a correlation between several properties of an object.
You can access more details from https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=6.1#validator-usingvalidator-classlevel

Overriding default Liferay Organization model

I need to customise Liferay's default behaviour: currently, each organization must hava a unique name -- I need to override this behaviour to allow duplicate names. Also, currently there are lots of entities in current Organization_ table in database.
Is it possible to override default model and remove uniqueness constraint while preserving old entities? If yes, how would I approach this?
Of course, I could just add unique suffixes to new saved entities and remove them on display, but this approach seems wierd.
Is it possible to override default model and remove uniqueness
constraint while preserving old entities?
Yes, it surely is, as you can override everything in Liferay
If yes, how would I approach this?
Sarcastic Approach
identify all the places, where Liferay handles Organizations and might implicitly rely on their uniqueness.
hope that I indeed found all the places
evaluate if it's feasible to change all those places to not rely on the uniqueness of the name any more
hope that I found everything, and that my changes make sense
set aside a lot of money to pay for future maintenance of my changes, when I need to adopt the changes to future versions of Liferay.
to 10. determine that it's not worth it and move on to an alternative solution
Alternative Approach:
Determine where this new display is required
implement alternative name, e.g. through Expandos (Custom Fields)
change display where needed to show the Expando values instead of the organization's name.

implementing dynamic class with using hibernate annotation

I want to implement a class which its fields could change (add new fields) through time. The problem is that I want to give my client this ability to do this himself by just completing a form of what field and which type he wants and then the change will be done automatically!
Does anyone have any idea how can I implement this class and make this change in my database using hibernate annotation?
You should use a map of name-value pairs. Maps are supported by Hibernate per se, and their contents are dynamic.
You definitely can't make that change using Hibernate Annotations, since annotations can only be attached to a class at compile time. However if you want to change the structure of your class at runtime (add fields, methods, etc.) you will have to recompile the class and recreate the database mapping Hibernate uses to access your database.

Locale based validation

My project have two main requirements
1) Different set of rules applied to same object at insertion and while updating it.
2) Different validation rules based on locale.
In ADDRESS object STATE field requires different validation rules
For USA: STATE cannot be NULL.
For everywhere else it can be NULL.
For first requirement i am already using GROUPS.
Is there a way to achieve second requirements.
I am using:
Hibernate Validator 4.0.1 GA
Hibernate 5.2.6
I would make the country (Locale based or not is up to you) part of the Address and use a custom class-level constraint to do the validation.
This question got answered on the Hibernate Validator forum. Best way to go is a class-level constraint or a Validator instance per Locale. I really wouldn't recommend the latter, but it's a possibility.

Categories