I was wondering if it was possible to use Java Bean Validation in hibernate, and how they integrate with each other.
I have a stack that consists of a Jax-rs API, and JPA in my data layer.
I was wondering if I it could use Java Bean validation to validate my Hibernate Entities, without using Spring.
Could I use the annotations from hibernate along with the ones from the javax.validation.contraints together
for example:
#Column(nullable = false)
#Size(min =8, max = 12)
#NotNull(message = "Phone Number must be entered")
private String phoneNumber;
here I specify that I the column, can't be null through hibernate and the bean validation.
Is this a good practice?
Or is there an alternative to validating data in hibernate, without bean validation like such?
The Bean Validation specification integrates with Hibernate and all other implementations of the JPA 2.x specification. I explained that in great detail in my article How to automatically validate entities with Hibernate Validator.
Let me give a quick summary:
If you add an implementation of the Bean Validation specification, e.g., Hibernate Validator, to your project, Hibernate automatically triggers the validation before inserting and updating an entity. You can customize that and also trigger validation before removing an entity. I explained that in more details in my article.
You can use all features of the Bean Validation specification, including custom validation rules, to validate your entity attributes. I used that here to validate that the value of an entity attribute is within a defined range and here to check that only one out of 2 associations is set.
The example mapping that you posted in your question is a very good practice!
The #Column(nullable = false) part is not strictly necessary because the validation rule already ensures that the attribute can't be null.
Since Hibernate also have their own validation annotations, for example #NotBlank, I don't think it's a bad practice to use javax.validation.constraint here. As far as I know, Hibernate even tries to consider all of these annotations.
So for example a field annotated with #NotNull will not be nullable in the generated table (so adding nullable = false is redundant), a String field annotated with #Size(max=2047) will be a varchar(2047) in MySQL instead of the default varchar(255).
This can be useful to read: http://hibernate.org/validator/
The whole reference docs for the project: https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#preface
EDIT: Based on Thorben Janssen's answer, the rest of my original answer below this can be discarded :)
I'm unsure if some more complicated constraints (for example a regular expression for phone numbers) are automatically enforced at the data layer or not. For example if you have a #Pattern for your phoneNumber field, that will work when your input is deserialized into your object. But if your setter methods dont have the same validation constraints, you might have an object in memory from some source with an incorrectly formatted phoneNumber that could be saved to the database. The safest way to use these constraints would probably include using programmatic validation with Validator.validate() before your database saves and updates.
Since Hibernate also have their own validation annotations, for example #NotBlank, I don't think it's a bad practice to use javax.validation.constraint here. As far as I know, Hibernate even tries to consider all of these annotations.
So, for example, a field annotated with #NotNull will not be nullable in the generated table (so adding nullable = false is redundant), a String field annotated with #Size(max=2047) will be a varchar(2047) in MySQL instead of the default varchar(255).
Related
I would like to ask if there exists a sane way to validate all string fields/values in a JSON #RequestBody of the MVC controller:
all fields of String type are validated by default, unless overridden by special annotation
the validation should check allowed characters and length
Solutions that I know of, but do not seem ideal for the use-case:
javax.validation via annotations -- one must not forget to add the annotation, the validation should be performed on every string unless said otherwise
org.springframework.validation.Validator most likely possible, but quite a lot of custom reflection code
some kind of component scan in unit test that checks that classes with certain suffix in name (*DTO?) does have all String fields annotation with validation annotation
use javax.validation + code-review
We all know that we can use xsd to validate xml instance. If you want to go ahead with JSON as well. Maybe you need checkout json schema.
As for java validator. You can refer to here
Hope it can help.
The NamingStrategy was already being marked as deprecated in Hibernate 4.2/4.3 (HHH-7079). Starting with Hibernate 5, now it will shipped with two replacements(?) interfaces ImplictNamingStrategy and PhysicalNamingStrategy (HHH-7078) and have finally ditched support for the old NamingStrategy. That's why Spring's upcoming Hibernate5 supported has even removed the configurer namingStrategy() and favor of implicitNamingStrategy() and physicalNamingStrategy(). So far, so good.
Although it is mentioned in some documents (i.e. in the incomplete working-5.0-migration-guide.md) and in (generated) release notes for the upcoming Hibernate 5 (as of today), I've found no concrete example how to use these actually.
Perhaps I've missed something, but neither the JavaDoc nor the issues shows any evidence of the idea both strategy types. Furthermore I've already one strategy based on NamingStrategy: a custom OracleNamingStrategy which is based on the well-known one.
While I'm interested in a proper solution in code (obviously), the actual issue is getting a working migration document and/or the conceptual idea of the restructured naming strategy.
Also related:
ImprovedNamingStrategy no longer working in Hibernate 5
Put below key value pair in your hibernate configuration file
hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
If you are providing #Table and #Column annotation in your entity classes with names provided with an underscore i.e. user_id i.e. #Column(name="user_id"), it will take the column name as user_id; if you give it as userid then it will change to user_id if you use no strategy or implicit strategy (specifically spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl). So, if you want a strategy where the entity attribute name changes to one with underscore and lowercase letters i.e. something from userId to user_id, you should use implicit or no strategy (which actually uses implicit strategy).
If you don't want your naming strategy to add an underscore to the column name or class name, then the strategy that you need to use would look like:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl. The things that you provide in annotations #Table and #Column’s name attribute would remain as it is.
If you don't want to provide annotations and want to manually handle the table name and column names, you should extend the class org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl and override the required methods. If you still use annotations for some of the cases here, remember the overridden methods will apply on the names written in those annotations.
spring.jpa.hibernate.naming.physical-strategy=example.CustomStrategy
When I looked among the standard constraints in Bean Validation API (JSR-303), I found the NotNull.List annotation. Its description is:
Defines several #NotNull annotations on the same element
This is valid syntax:
#NotNull.List({#NotNull, #NotNull})
private Object myObject;
But it makes no sense. Either the object is null or it is not. When would you use this annotation?
There are several other similar annotations like AssertFalse.List and AssertTrue.List.
You can have multiple #NotNull annotations that are mutually exclusive based on the group attribute.
#NotNull.List({#NotNull(groups=Foo.class,message="Some message!"),
#NotNull(groups=bar.class, message="Some other message!"})
private Object myObject;
I do agree it's a little silly for this example since only the payload and message can be affected, but it's probably there to remain consistent with the other annotations.
See here for more details.
As to the #NotNull case, multiple #NotNull annotations might be needed
for different validation groups as #dfb explained. But the same may be
accomplished by listing those groups in the groups attribute.
This is well explained here with test cases
In the bean validation API javadoc, for every constraint annotation,
there's a corresponding .List annotation. For example, for #NotNull,
there's #NotNull.List, for which JavaDoc says:
Defines several #NotNull annotations on the same element
What would you accomplish with multiple #NotNull annotations that you
cannot accomplish with one #NotNull?
There is the #NotNull annotation which validates that a certain object is not null.
There is the #NotEmpty annotation which validates that a certain collection/map/string/... is not empty.
Is there also an annotation which valides that a certain collection/map does not contain any nulls? I am unable to find it. It seems so basic, that I believe it must be in the JSR-303 spec.
Bean Validation 2.0/Hibernate Validator 6.0
Bean Validation 2.0 (of which Hibernate Validator 6.0 is the reference implementation) allows using its validation annotations directly on generic type arguments. This is noted in the Hibernate 6.0 release documentation:
Hibernate Validator 6.0 is the Reference Implementation of the Bean Validation 2.0 specification so it comes with all its new features:
First class support of container element constraints and cascaded validation (think private Map<#Valid #NotNull OrderCategory, List<#Valid #NotNull Order>> orderByCategories;);
If the project is using Java 8 with Bean Validation 2.0, this feature can be used to achieve your stated goals:
List<#NotNull String> noNullsList;
Map<#NotNull String, #NotNull String> noNullKeysOrValuesMap;
Bean Validation 1.2/Hibernate Validator 5.2
Hibernate 5.2 (with Bean Validation 1.2) added a limited version of the feature to allow validation annotations directly on generic type arguments. However, none of its built-in Bean Validation or Hibernate Validation constraints could be used in this manner, as the annotations do not specify ElementType.TYPE_USE for backwards-compatibility reasons. Additionally, type argument constraints could be specified for map values but not map keys. This is all described in the Hibernate Validator 5.2 documentation:
Starting from Java 8, it is possible to specify constraints directly on the type argument of a parameterized type. However, this requires that ElementType.TYPE_USE is specified via #Target in the constraint definition. To maintain backwards compatibility, built-in Bean Validation as well as Hibernate Validator specific constraints do not yet specify ElementType.TYPE_USE.
[...]
When applying constraints on an Iterable type argument, Hibernate Validator will validate each element.
[...]
Type argument constraints are also validated for map values. Constraints on the key are ignored.
Summary
In summary, if you are using Java 8 with Bean Validation 2.0 (such as Hibernate Validator 6), you can annotate the generic list & map type arguments with #NotNull.
If you are using Java 8 with Bean Validation 1.2 and Hibernate Validator 5.2, you can write a custom #NotNull validation annotation with TYPE_USE in its definition, and apply it to the generic type of the collection or map value.
If you are not on Java 8 or are on a version of Hibernate Validator prior to 5.2, you would need a custom constraint to apply to the map or list to verify that every element of the collection or map is non-null.
There is no such built-in constraints. You can easily write your custom constraints, eg #NoNullElements, which does what you want. Refer to the Refer to the documentation http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-customconstraints to see how to write custom constraints.
I had the same Problem. And the only solution I found was, adding a null validation into the setters of the Entity. If the submitted value is null -> return. I know thats pretty ugly but the only way I know how to avoid exceptions.
It seems that #Basic annotation on a java variable only declares that the variable must be saved as a column with NOT NULL constraint. Is that correct ?
This post says that:
#Basic(optional = false) #Column(nullable = false) The #Basic
annotation marks the property as not optional on the Java object
level. The second setting, nullable = false on the column mapping, is
only responsible for the generation of a NOT NULL database constraint.
The Hibernate JPA implementation treats both options the same way in
any case, so you may as well use only one of the annotations for this
purpose.
I am confused. What does this mean - The #Basic annotation marks the property as not optional on the Java object level. How is a property or variable "optional" at Java level ?
The Hibernate JPA implementation will treat both the same only in terms of schema generation, that is the column will be created with a not null constraint.
Using optional = false however also allows for Hibernate (and I suppose other implementations) to perform a check and throw an exception prior to flushing to the database if the non-optional field is null. Without this you would only get an Exception thrown after the attempt to insert.
From Pro JPA:
When the optional element is specified as false, it indicates to the
provider that the field or property mapping may not be null. The API
does not actually define what the behavior is in the case when the
value is null, but the provider may choose to throw an exception or
simply do something else. For basic mappings, it is only a hint and
can be completely ignored. The optional element may also be used by
the provider when doing schema generation, because, if optional is set
to true, then the column in the database must also be nullable.
Having optional=false can also affect Entity loading in Hibernate. For example, single-ended associations are always eagerly loaded in Hibernate unless the association is marked as optional=false.
See: https://stackoverflow.com/a/17987718/1356423 for further explanation.
The authoritative answer to the meaning of an api element is of course the api documentation, i.e. the javadoc. For the #Basic annotation, this writes:
The simplest type of mapping to a database column. The Basic annotation can be applied to a persistent property or instance variable of any of the following types: Java primitive types, wrappers of the primitive types, String, java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.Timestamp, byte[], Byte[], char[], Character[], enums, and any other type that implements java.io.Serializable.
The use of the Basic annotation is optional for persistent fields and properties of these types. If the Basic annotation is not specified for such a field or property, the default values of the Basic annotation will apply.
What are the values of the Basic annotation? The Javadoc explains them, too:
public abstract FetchType fetch
(Optional) Defines whether the value of the field or property should be lazily loaded or must be eagerly fetched. The EAGER strategy is a requirement on the persistence provider runtime that the value must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime. If not specified, defaults to EAGER.
and
public abstract boolean optional
(Optional) Defines whether the value of the field or property may be null. This is a hint and is disregarded for primitive types; it may be used in schema generation. If not specified, defaults to true.
Therefore, if you set optional to false, the persistence provider may throw an exception when you try to persist or update an object where the property is null. This can be useful if your business rules say that null is not a legal value.
Note
At least when using hibernate, nullability is better expressed with the corresponding Bean Validation annotation (#NotNull), as this annotation is both understood by hibernate and can be used by other layers on an application (for instance when validating user input).