JPA bean validation use field or property access? It should use the same access type for both JPA and validation. How to tell validation provider which one should be used?
public class Foo {
#NotNull
private String name;
#Size(20)
public String getName() {
}
}
Bean Validation constraints can be on both the field and the property getter. The spec however recommends using only one access strategy, and when using JPA use the same access strategy used for persistence.
Here is the relevant part of the Bean Validation spec (see section 5.1.2):
Constraint declarations can be applied on both fields and properties
for the same object type. The same constraint should however not be
duplicated between a field and its associated property (the constraint
validation would be applied twice). It is recommended for objects
holding constraint declarations to adhere to a single state access
strategy (either annotated fields or properties).
NOTE
Java Persistence and Bean Validation For maximum portability, persistent
properties hosting Bean Validation constraints should use the same
access strategy used in Java Persistence. In other words, place your
Bean Validation constraint annotations on the same element (field or
getter) as your Java Persistence annotations.
When a field is
annotated with a constraint declaration, field access strategy is used
to access the state validated by such constraint.
When a property is
annotated with a constraint declaration, property access strategy is
used to access the state validated by such constraint.
Related
First of all I hope this question is allowed because I guess its a rather framework-specific question (Symfony). I am running into the following problem:
A form is submitted and checked for validity for creating a new 'Toernooionderdeel' and as a result the Persist and Flush operations of Doctrine for this Entity are to be called attempting to put the newly created entity into the database. Fairly basic stuff to this point. But the form fails at ->isValid() before persisting and flushing can commence.
In my case the Constraints are applied on properties in various ways through annotation.
#Assert\Valid specifically is used on properties that define ManyToOne relationships with other entities and it all works fine, until...
I attempt to use #Assert\Valid on a property of 'Toernooionderdeel' called '$toernooi' which represents a ManyToOne relationship (Toernooionderdeel -> Toernooi).
The difference between this one and the other relationships I validate in the same way is that this 'Toernooi' Entity is derived from another entity, where the other entities aren't.
Despite obviously having a 'Toernooi' defined under the '$toernooi' property of 'Toernooionderdeel', the Constraint detects it as a violation and thus the form doesnt pass validation.
What things do i have to consider when doing this type of validation (using Constraints) on an 'advanced' entity construction like this? Has any of you done this before and if so, how did you do it?
When the entity referenced in a property ("child") is validated in the parent object via Assert\Valid, it's validity is also checked. When the child entity isn't valid, the parent isn't valid either (transitive).
I am having a difficult time trying to understand the Transient annotation of JPA. I assume the fields noted with Transient annotation will be stored in a local cache and not persisted in DB. I basically like to know when will it be cleaned up from the local cache?
I am using this for a table to store its intermittent status and I use this value in a method that is returned after I call an external service. Is this an appropriate use case? If so, what will be the life time of such a transient field?
#Entity
class Sample {
#Transient
String fieldOne;
transient String otherField;
}
fieldOne is not transient (has not transient keyword), so is serialised (to/from cache, network, file or other sources). But JPA will not store it in database, because annotation denies.
otherField is not seriazable, has transient keyword (i.e. after getting from cache engine, or network can/will be null), but is pesissted in JPA database with default behaviour
This is not academic discussion, sometimes it is useable. Usually values computed from others, or hashed /encrypted /hidden fields.
I read this in the EJB/JPA Book:
"Even if you mark the property as LAZY for a #Basic type, the persistence provider is still allowed to load the property eagerly. This is due to the fact that this feature requires class-level instrumentation. It should also be noted that lazy loading is neither really useful nor a significant performance optimization. It is best practice to eagerly load basic properties."
QUESTION 1)
If I set property as an LAZY, why e persistence provider is still allowed to load the property eagerly? when this happens? and why? is this for primitives only?
QUESTION 2)
"The #Basic annotation is the simplest form of mapping for a persistent property. This is the default mapping type for properties which are primitives, primitive wrapper types"
If I use does not use primitive or wrapper (for instance I use my class object), will he persistence provider is still allowed to load the property eagerly?
QUESTION 3)
"You do not need to tell your persistence manager explicitly that you're mapping a basic property because it can usually figure out how to map it to JDBC using the property's type."
As I understand this happens when I use primitives or wrappers, don't I? And how does it figure out how to map? Is there any obvious rule?
QUESTION 1)If I set property as an LAZY, why e persistence provider is
still allowed to load the property eagerly? when this happens? and
why? is this for primitives only?
Because of performance issues: the JPA provider has the right (according to the JPA spec) to decide that it is better to fetch the field eagerly. This is valid also for wrapper fields & Strings. It is not specified when this happens, which means that can happen when the JPA provider considers it needed.
QUESTION 2)"The #Basic annotation is the simplest form of mapping for
a persistent property. This is the default mapping type for properties
which are primitives, primitive wrapper types"
If I use does not use primitive or wrapper (for instance I use my
class object), will he persistence provider is still allowed to load
the property eagerly?
Actually yes, also for relationships you have the same rule, although almost always the JPA provider will consider your hint. Of course: when you have a field of type YouClass, you are not allowed to annotate it with #Basic and must use #ManyToOne-like annotations. You will read further about them.
QUESTION 3) "You do not need to tell your persistence manager
explicitly that you're mapping a basic property because it can usually
figure out how to map it to JDBC using the property's type."
As I understand this happens when I use primitives or wrappers, don't
I? And how does it figure out how to map? Is there any obvious rule?
That happens will all types listed in the documentation of the #Basic annotation, not only those that you enumerated. The rule is pretty simple: String types are mapped as VARCHAR/CHAR like columns, number-fields like NUMBER (or DECIMAL) and so further.
i'm trying to figure wether there's a difference betweeen anotating (let's take #id as an example) a getter method and the concerned field directly , in case i annotate the field , does JPA use some kind of reflection to invok the corresponding getter ?
because in my case i'm trying to obfuscate my entity classes , so i'm looking for a way to keep the business logic since the getters will be renamed into something like aaa() .
Here's what the section 2.3.1 of the JPA2 specification says:
By default, a single access type (field or property access) applies to
an entity hierarchy. The default access type of an entity hierarchy is
determined by the placement of mapping annotations on the attributes
of the entity classes and mapped superclasses of the entity hierarchy
that do not explicitly specify an access type. An access type is
explicitly specified by means of the Access annotation[6], as
described in section 2.3.2. When annotations are used to define a
default access type, the placement of the mapping annotations on
either the persistent fields or persistent properties of the entity
class specifies the access type as being either field- or
property-based access respectively.
When field-based access is used, the object/relational mapping annotations for the entity class annotate the instance variables, and
the persistence provider runtime accesses instance variables directly.
All non-transient instance variables that are not annotated with the
Transient annotation are persistent.
When property-based access is used, the object/relational mapping annotations for the entity class annotate the getter property
accessors[7], and the persistence provider runtime accesses persistent
state via the property accessor methods. All properties not annotated
with the Transient annotation are persistent.
Mapping annotations must not be applied to fields or properties that are transient or Transient.
All such classes in the entity hierarchy whose access type is
defaulted in this way must be consistent in their placement of
annotations on either fields or properties, such that a single,
consistent default access type applies within the hierarchy. Any
embeddable classes used by such classes will have the same access type
as the default access type of the hierarchy unless the Access
annotation is specified as defined below. It is an error if a default
access type cannot be determined and an access type is not explicitly
specified by means of annotations or the XML descriptor. The behavior
of applications that mix the placement of annotations on fields and
properties within an entity hierarchy without explicitly specifying
the Access annotation is undefined.
So, if you want to avoid problems with the obfuscation, then annotate the fields and not the getters, consistently, or use the #Access annotation to force field access type.
JPA allows for two types of access to the data of a persistent class. Field access which means that it maps the instance variables (fields) to columns in the database and Property access which means that is uses the getters to determine the property names that will be mapped to the db. What access type it will be used is decided by where you put the #Id annotation (on the id field or the getId() method).
I have a ComplexType that must implement IList<T> (background info here).
Unfortunately, Entity Framework complains about the indexed property required of that interface
[NotMapped]
public T this[int index]
(Note it's decorated with the NotMapped data annotation).
I get a DbUpdateException at runtime with the inner exception
Indexed properties are not supported.
If I comment out that the class implements IList<T> and comment out the indexed property, instances of the class persist as expected.
Is there some way for a complex type to implement IList<T> to be persisted by Entity Framework Code First?
Entity framework doesn't support open generic entities and I believe the same is true for complex types. The only way is to define specific type derived from closed generic type as you shown in your linked question.
Also there is some well known bug that mapped class must not have indexer.