What does #Basic annotation really do? - java

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).

Related

Difference JPA/Hibernate persists fields of type List<String> vs List<MyPersonEntity> vs List<NonEntityClass>

I know we persist collections (List, Set, Map, Collection) in two ways - annotate collection field with some JPA (javax.persistence) relation mapping annotation (#OneToMany, #ManyToMany) or use #ElementCollection JPA annotation.
1). Does JPA (or Hibernate underlying JPA) without above #OneToMany/#ElementCollection annotations persist List, Set, Map, Collection fields (fields not annotated with anything, their class is #Entity and #Id + #GeneratedValue present - and no more annotations).
Any primitive, enum and Serializable fields shall be persisted (as per JPA) - so collection fields shall also be persisted and then retrieved with entityManager.find - right? OK, order not preserved so I need to use #OrderColumn or #OrderBy JPA annotation (or Hibernate-specific deprecated #Sort or recommended now #SortNatural or #SortComparator ) additionally.
So my guess is that List<String> and List<MyPersonEntity> would be persisted and retrieved (as a field) without any annotations, but I'm not sure about List<MyNonEntityClass> (I think same goes for it).
What is the differnrece in persisting (allowed annotations, what can be persisted, what can be persisted as field without any annotations) List<String> vs List<MyPersonEntity> vs List<SomeNonEntity> exactly? Is there any such difference?
I googled a lot, read a few manuals, but found no direct answers.
Thorben Janssen writes
An #ElementCollection enables you to map a Collection of values **that are not an entity itself. **
It implies to me that List<MyPersonEntity> is persisted to DB without any annotations on List field, but List<OrderNotEntity> needs either #ElementCollection or #OneToMany/#ManyToMany annotation to be persisted. Does it throw an error or just silently fails to persist and then resolves to null when retrieved from database with entityManager.find?
[This][1] implies that #ElementCollection is needed only for List<BasicType> (List<String>, List<Integer>, etc) and List<Embeddable>, but not List<EntityClass>.
3). Can I use #ElementCollection with List<SerializableNonEntityClass> (any Serializable class is Basic, right?), List<MyEnumColor> (all enums are serializable), List<java.util.Date>, List<java.sql.Time> (also basic type), List<Set ?
JPA [Specification][2] does not define term "basic type", but provides a list of what can be annotated with #Basic:
11.1.6 Basic Annotation The Basic annotation is 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,
java.lang.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 Serializable. As described in Section
2.8, 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
2.8 Mapping Defaults for Non-Relationship Fields or Properties If a persistent field or property other than a relationship property is not
annotated with one of the mapping annotations defined in Chapter 11
(or equivalent mapping information is not specified in the XML
descriptor), the following default mapping rules are applied in order:
• If the type is a class that is annotated with the Embeddable
annotation, it is mapped in the same way as if the field or property
were annotated with the Embedded annotation. See Sections 11.1.15 and
11.1.16. • If the type of the field or property is one of the following, it is mapped in the same way as it would if it were
annotated as Basic: Java primitive types, wrappers of the primitive
types, java.lang.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, any
other type that implements Serializable.
I don't understand that reference to section 2.8. So if I don't use #ElementCollection - no problem, mapping to DB also succeeds and everything is persisted just fine???
[1]: https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection#:~:text=It%20is%20meant%20to%20handle,a%20collection%20of%20String%20s)
[2]: https://download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf?AuthParam=1648386141_7549cef1d21f5581b4966d8d8ef70de4

Using bean Validation in hibernate

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).

How to migrate a Hibernate NamingStrategy to (Implicit|Physical)NamingStrategy? Where is the documentation?

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

java/beans validation - collection/map does not contain nulls

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.

Persisting Serializable Objects in Hibernate

I am attempting to persist objects that contain some large Serializable types. I want Hibernate to automatically generate my DDL (using Hibernate annotations). For the most part, this works, but the default database column type used by Hibernate when persisting these types is tinyblob. Unfortunately, this causes crashes when attempting to persist my class, because these types will not fit within the length of tinyblob.
However, if I manually set the type (using #Column(columnDefinition="longblob"), or more portably #Column(length=500000)), it works fine. Is there any way to make the default binary type longblob instead of tinyblob, so that I don't need to manually specify the #Column annotation on each field?
ExampleClass.java:
public class ExampleClass
{
#Column(columnDefinition="longblob")
ExampleSerializable ser1;
#Column(columnDefinition="longblob")
ExampleSerializable ser2;
...
}
ExampleSerializable.java:
public class ExampleSerializable implements java.io.Serializable
{
// MANY Fields
}
EDIT
Since there seems to be some confusion: annotating each field with #Column(columnDefinition="longblob") (or more portably: #Column(length=500000)), already works. I am looking for a solution that does not require me to annotate each and every field.
I think (didn't test it) that Hibernate will generate a tinyblob, blob, mediumblob column depending on the column length (respectively 255, 65535, 16777215) which defaults to 255. I would try to specify it (and this would be a portable solution).
Now, if really you want to force things, you'll have to extend the MySQL dialect (but this will harm portability).

Categories

Resources