Enumerate and change persistent fields in a generic (indirect) manner - java

In Hibernate 4.x, is there any way to get a list of persistent fields at runtime? By persistent fields I don't mean DB column names, but POJO field names or property names (depending on access type for a particular entity). Also, is there a method to get/set a persistent field's value given a field name as a string, regardless of whether it's a field or property name?

It seems that everything I need (and more) is contained in ClassMetadata class (documentation).
I can get the metadata for a particular class by using SessionFactory.getClassMetadata(entityClass) and then use metadata.getPropertyNames(), etc.

Related

Hibernate Embeddable: validate on post load

I have an #Embeddable class with two fields: type and value. Both fields map to the corresponding database columns. The first one is enum and the latter one is an interface that has multiple implementations.
Only certain combinations of type and value are considered valid even if type and value are correct in isolation. How can I perform such validation, when I retrieve the entity that owns the #Embeddable from the database?
I could perform validation inside no-args-constructor of embeddable, but as far as I'm concerned, Hibernate creates new #Embeddable instance with no-args-constructor and then injects the values with Java Reflection API. Therefore, if I access these two fields inside the constructor they will be null.
Is there an approach to register some PostLoad hook for the #Embeddable classes that Hibernate will trigger? I though about declaring PostLoad inside the entity itself and then calling MyEmbeddable.validate directly. But I think it's a dirty approach.
I added the class-level annotation to validate the whole object. It did work. Check out this question for more details.

Java annotation to get the value of its field

Is it possible to pass the value of the parameter to the annotation?
For example:
#MyAnnot
final List<String> list;
I want the content of list to be passed to MyAnnot
What you are asking for is not possible using standard Java.
An annotation is a form of class whose instances may be attached to various elements of a program; e.g. classes, methods, fields, parameters and so on. For annotations with retention policy RUNTIME, an application use reflection to retrieve the annotations associated with a Class, Method, Field and so on.
The problem is that the annotations are associated with (effectively) syntactic elements, rather than instances of those elements. So for example:
public class Thing {
#MyAnnot
final List<String> list;
}
We can use reflection to find the Class object for Thing, and the Field object for list. And from there, we can get the #MyAnnot annotation associated with the Field.
However, the Class, Field and #MyAnnot instance are not associated with any particular instance of your Thing class. If you wanted to get the value of list via your #MyAnnot annotation (somehow) it would need to know (somehow) which instance you were talking about.
The other interpretation of your question is that want (somehow) that each time your application assigns to a Thing object's list variable, that value assigned is also passed to the #MyAnnot annotation. The JVM doesn't do that. It is not standard behavior for annotations. It would be theoretically possible to implement such a feature (with some heroic bytecode rewriting, for example) but I'm not aware of any examples.

How does a JPA provider access (private) field values when no getter/setter method are defined?

As entity class field can be mark as private when #Entity access mode is "Field" access , just wanted to understand how provider will able to access entity state in this case as fields are marked as Private and will not be visible outside class ?
Edit #1 - As you know , for field access , getter and setter method are optional. So I wanted to understand how provider will access the field when no getter/setter method are provided. Hope this clarify my question .
Referring to the official JPA specification (final version, JPA 2.1) in Section 2.2 (page 24) we find:
The persistent state of an entity is accessed by the persistence provider runtime either via JavaBeans
style property accessors (“property access”) or via instance variables (“field access”). Whether persistent
properties or persistent fields or a combination of the two is used for the provider’s access to a
given class or entity hierarchy is determined as described in Section 2.3, “Access Type”.
In Section 2.3.1 (page 27) this definition is made more concrete - with respect to your question:
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. [...]
• 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, and the persistence provider runtime accesses persistent state via the property accessor methods. All properties not annotated with the Transient annotation are persistent.
The term directly refers to an access strategy which allows the manipulation of an object's field (value) without the need to use getter/setter methods. In Java and for most OR-mappers (at least the ones I know of) this is achieved via Introspection - using the Java Reflection API. This way, classes' fields can be inspected for and manipulated to hold/represent data values from the (relational) database entries (i.e., their respective columns).
For instance, the provider Hibernate gives the following explanation in their User Guide:
2.5.9. Access strategies
As a JPA provider, Hibernate can introspect both the entity attributes
(instance fields) or the accessors (instance properties). By default,
the placement of the #Id annotation gives the default access strategy.
Important note:
Be careful when experimenting with different access strategies! The following requirement must hold (JPA specification, p. 28):
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.
Hope it helps.
The provider can use reflection to access a private field on a class instance.

The better solution to extend DTO object (Java, Hibernate)

I use EmailAlert bean as DTO to get data by means of Hibernate.
So, my class contains only fields that I have in DB.
But in some cases I need additional fields to be in EmailAlert to hold intermediate data. For example "caption" field - will be calculated on java side depends of user locale, time, etc.
So, I have some variants to solve this issue.
Add additional property (ex: caption) to EmailAlert bean, but do not map it with any field of DB table.
Drawback: In this case we have to do not use "caption" property in hashCode() and equals() because as:
It really don't have a matter - field holds only intermediate data
I am not sure it not be a cause of problem with cache and Hibernate itself.
I think it is very ugly to have a property of class but do not use it in equals() and hashCode() methods.
Someone can be confusing in the future with this logic.
Extend EmailAlert as EmailAlertExt with adding of "caption" property. And constructor that takes EmailAlert as argument.
But in this case I am not sure underwater stones in case I will store EmailAlert as EmailAlertExt bean again into DB.
Extend EmailAlert as EmailAlertExt2 with adding of "caption" property and take a refference to the original object. In this case EmailAlertExt2 will behave as original EmailAlert, but with additional property we need. In case we save EmailAlert we could call getOriginalValue() of EmailAlertExt2 that will return refference to original object.
Drawback: too many coding :)
Guys, which of these solutions is better? May be someone have other proposals?
Use '#Transient' it won't map to db hibernate will ignore this field
Extending a model object just because you want to separate mapped vs non-mapped fields is not a good idea. A good guideline would be to ask yourself the question "What is the difference between an EmailAlert and an EmailAlertX, and can I clearly define the situations where I would use one over the other?". If you cannot answer that question cleanly, or if you realize that you will always be using your subclass over the parent class, that is a sure sign that the parent class should be abstract or that you have too many classes.
In your particular case, it would make more sense to have both the mapped, and non-mapped properties on the same class, and to mark the non-mapped properties so that your ORM provider does not try to process them. You can do this by annotating these properties as being #Transient.
public class EmailAlert implements Serializable {
#Id
private Long id;
#Column(name = "recipient")
private String recipient;
#Transient
private transient String caption;
// Constructor, Getters/Setters, etc
}
Also, with respect to to your comment on hashcode/equals methods. You do not and should not include every property of a Java Bean in these methods. Only include those properties that are:
required to uniquely identify the object
are (fairly) guaranteed to have the same value over the lifecycle of the object
It sounds like the EmailAlert object you need at the moment is a business object, because of the "intermediate data" and "calculated on java side" bits.
Maybe use the EmailAlertDto object to populate the fields of the EmailAlertBusiness and store the extra caption field and the methods in the business object.

Java, Hibernate annotations, How to add methods to POJO object?

I am using hibernate annotations. How to add methods to POJO object? For example i have "getChildNodes" method, associated with database, but i want also add recursive method "getAllChildNodes". I get "org.hibernate.PropertyNotFoundException: Could not find a setter for property progress in class" exception when i do it.
If I interpret this as "how do I add a method that is NOT related to persistence" then you need to use the #Transient annotation on the getAllChildNodes() method
There are two ways of defining the structure of your entity.
using annotations on the instance variables of your entity or
using annotations on the getter methods of your entity
When using the annotations on getter methods, Hibernate assumes that every getXxx (and isXxx for boolean types) represents definition of a persistent property. And this holds even if that particular getter does not contain any annotations, as happens in your case.
Hibernate also expects to find a matching setter method for each persistent property. And in your case that is what's missing and causes the exception.
You can solve this problem by declaring your custom getter as #Transient that says this getter does not represent a persistent property. Another way would be to convert the entity to use annotations on the instance variables. The latter would be my personal choice.
Open up the .java file and write a method named getAllChildNodes().
Hibernate doesn't write code for you, it maps fields in your database to your code. That's all. If you want to have extra logic in your domain/model classes besides the normal getters and setters for your properties, you'll have to add them yourself.

Categories

Resources