Hibernate Embeddable: validate on post load - java

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.

Related

Querying Mapped Superclasses or Equivalent

I have three classes that are subclasses of the abstract superclass Automobile. I'm using the single table inheritance model and a #MappedSuperclass for the automobile class. The subclasses are Car, Truck, and Van.
I want to query the automobile class, but have the different subclasses returned. I've written a couple queries and done some research, but it seems like it is not possible to query against MappedSuperclasses. I have also tried to do NativeSqlQueries, but I can't seem to be able to figure out how to specifiy multiple ResultSetMappings.
Is there anyway to accomplish this?
You cannot use a mapped-superclass in the query. If you want to use Automobile in the query, don't mark it as mapped-superclass, instead mark it as an entity.
Following is from the JPA 2.0 Spec, second paragraph is what's relevant in your case -
2.11.2 Mapped Superclasses
An entity may inherit from a superclass that provides persistent entity state and mapping information, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.
A mapped superclass, unlike an entity, is not queryable and must not be passed as an argument to EntityManager or Query operations. Persistent relationships defined by a mapped superclass must
be unidirectional.

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.

Is there any reason to not generate setters and getters for #Id fields in JPA?

Assuming a JPA entity with (for example) an long id generated automatically:
#Entity
#AutoProperty
public class SomeItem {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long Id;
...
}
Is there any reason to not generate setter and getters for this Id? One might be tempted to not generate a setter for example, since it is the responsibility of JPA to generate the ID.
I see that other comments has misguided you so I feel myself obliged to elaborate on this issue a bit, even though I can't give you a scientific and complete answer. #vcetinick wrote the current accepted answer:
You may find that you may be able to get away [..] from the persistence side of things.
This quote in particular is wrong. All depends on where you put your #Id annotation. The specification says:
If the entity has field-based access, the persistence provider runtime
accesses instance variables directly.
Thus you are not required in any way to provide a setter or getter. Because you annotated your field and not a getter method (annotating the setter method will be ignored and have no bearing).
However, if you write a getter method, and annotated this method with your #Id annotation instead of your field, then we would tell our persistence provider to access our field through the accessor (getter) and mutator (setter) methods and not use reflection. In that case, both a getter and a setter should be present. The book Pro JPA 2: Mastering the Java™ Persistence API writes on page 71 (bold markup by me!):
When property access mode is used, the same contract as for JavaBeans applies, and there must be getter and setter methods for the persistent properties. The type of property is determined by the return type of the getter method and must be the same as the type of the single parameter passed into the setter method. Both methods must be either public or protected visibility.
Therefore, I usually annotate my id field, and write both a setter and getter method, but the setter method I give protected access. I just don't want any other pieces of code to have easy write access to such an important field. I don't know if this would cause problems in other domains. I'm no expert. But I don't find any rationale either as to why not setup an id attribute in this way. See also the Netbeans forums.
You may find that you may be able to get away without putting a getter/setter on the JPA Entity from the persistence side of things. But if you start dealing with entities that are serialized from other sources, even from your view in some cases, you will need a way to set the ID of the entity to let JPA know that it is dealing with an existing entity, if you cant set the id, then the persistence layer will just treat it as a new Object.
Id is your primary key without it you will never able to insert records in the database.
In your case #GeneratedValue(strategy=GenerationType.AUTO) it ensures that id will be generated for each persist but then also you will need a method to access it since it is primary identification of entity you should provide access to it .
Its like you asking some person his name and he doesn't provide it to you and you would thing he is just being rude .

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.

Given a java object can I confirm its a bean persist-able by hibernate

there are times when I want to pass in an object to say an Auditing layer whose sole job is to persist the entities (no matter what type) , but since this is a public API, I want to ascertain that the passed in object is a hibernate entity bean and then only try the saveOrUpdate()
I'm sure that at runtime you could use some sort of jedi-reflection-trick to find out weather your entity is a Hibernate entity (An approach I would not recommend), however, under normal circumstances, you dont have to worry if its not a hibernate entity, the Session.saveOrUpdate() method will throw an HibernateException explaining the reason why it couldn't save and/or update it.
There is nothing you can do to prevent your public method from being called with an arbitrary object type. What you can do is document your API as to what type of entities it does expect and the resulting behavior if something different is passed to it.
There are a few methods on the Session interface which take a Class argument, like createCriteria(Class) and getCurrentLockMode(Class). I haven't tried this, but you could try passing the class of your object to one of those methods. If you're lucky, then if it's not an entity class, then an exception will be thrown.
Not elegant, but it's all I got :)
http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/SessionFactory.html#getClassMetadata(java.lang.Class). From JavaDoc, Returns:
The metadata associated with the given entity; may be null if no such entity was mapped.

Categories

Resources