org.hibernate.annotations vs. javax.persistence - java

Is it a bad idea to use the annotations from the
javax.persistence package
instead of using the
org.hibernate.annotations annotations
I know that using javax.peristence does introduce yet another dependency. But if I ignore that, what are the pros/cons?

Quite the opposite.
Hibernate is an implementation of the Java Persistence API, and where possible, you should use the standard annotations (in javax.persistence). This way, you could theoretically run your code on other JPA implementations.
Only when you need Hibernate-specific functionality should you use the Hibernate annotations.
The extra dependency is only on the JPA interface/annotation jar files and very light.

Another cons in:
http://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/
where this:
#OneToMany(fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST,CascadeType.MERGE },
mappedBy = "stock")
public Set<StockDailyRecord> getStockDailyRecords() {
return this.stockDailyRecords;
}
with this:
stockDailyRecords.setStock(stock);
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stock);
session.getTransaction().commit();
won't work as #OneToMany is from JPA, it expects a JPA cascade – javax.persistence.CascadeType. However when you save it with Hibernate session, org.hibernate.engine.Cascade will do the following check:
if ( style.doCascade( action ) ) {
and Hibernate save process will causing a ACTION_SAVE_UPDATE action, but the JPA will pass a ACTION_PERSIST and ACTION_MERGE, it will not match and cause the cascade to fail to execute.

I used javax.persistence annotation, and when I replaced Tomcat 6.0 with my Glass Fish, then Tomcat 6.0 included another javax.persistence package that messed everything. I don't think it's a good idea to use javax.persistence annotation. God know what the hell happened with Tomcat and javax.persistence!

Officially recommended to mix JPA and Hibernate annotations in the case of setting cascading options, see
Hibernate docs. 2.4.7. Cascade. If you using only JPA annotations, in case of unidirectional mapping (no field of Foo type in Employer.java) you still getting "cannot save transient object Employer" in the call session.SaveOrUpdate. Cure is using hibernate-style #Cascade together with cascade={...}:
class Foo {
#OneToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
#Cascade(org.hibernate.annotations.CascadeType.REPLICATE)
public Collection<Employer> getEmployers()
...
}

Related

Hibernate CascadeType inside association annotation vs outside

What is the difference between the CascadeType options inserted inside the #OneToMany annotation and those inserted inside #Cascade? which is the priority, is one of the two ignored?
#OneToMany(mappedBy="page", fetch=FetchType.EAGER, cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
#Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE})
private List<Tag> tags;
There is no difference.
If OneToMany is a JPA annotation (javax.persistence.OneToMany) you can not use Hibernate 'cascade' inside. You have to use JPA cascade.
#Cascade annotation is specific to hibernate and not JPA.
When you write something like : CascadeType.SAVE_UPDATE, that mean that the cascade is used when you use hibernate method 'saveOrUpdate', so when you use hibernate methods to save, delete, ... objects use #Cascade annotation. If you use JPA methods use cascade inside #OneToMany annotation.
The Hibernate Documentation, is clear on this issues.
They espically recommand to use both in case of SAVE_UPDATE.
As shown in hibernate documentation we can use both cascadeType attribute and #cascade annotation :
#OneToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
#Cascade(org.hibernate.annotations.CascadeType.REPLICATE)
public Collection<Employer> getEmployers()

Can JPA entities be serialized to disk?

I have two machines:
A) Windows XP, JDK 1.7.45
B) Windows Server 2003, JDK 1.7.45
In machine A I can successfully serialize an object to file system and its children and deserialize back.
In machine B, when I deserialize, the children objects are missing. No exception at any stage is thrown.
If I copy the serialized file from A to B then deserialization in B creates the child objects just fine.
This points to a problem in serialization in B.
The problem does not happen with very simple objects. But, when I use objects annotated with JPA, the problem happens.
#Entity
#Table(name="...")
#NamedQuery(name="Category.findAll", query="SELECT c FROM Category c")
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="...")
private long id;
#Transient
private List<Category> subCategories; //These go missing
...
}
This problem happens for only certain but not all JPA entity classes.
Any idea what might be causing this? Can JPA entities be serialzed without issues? My eventual goal is to cache JPA entities in Couchbase. This works in A, but fails in B. Even simple disk based serialization has problem in B as described here.
There is nothing that prevents you from serializing JPA entities, after all they are POJOs. But what could be happening is that when you try to deserialize it you can't because in the other JVM it doesn't have in the classpath the JPA annotations. Anyway, it should be throwing an exception, so recheck your log.
Here is the tool for you:
EclipseLink MOXy is an implementation of JAXB (JSR-222) specification. As EclipseLink also provides a JPA implementation many of its extensions are aimed at mapping JPA entities:
#XmlInverseReference for supporting bidirectional relationships (see: http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html)
#XmlPath for mapping embedded IDs (see: http://blog.bdoughan.com/2010/07/xpath-based-mapping.html).
#XmlJoinNodes (similar to JPA's #JoinColumns) when you need to map by key/foreign key.

Java EE Example not working

In this doc we can see example of usage #CollectioTable annotation
I wrote the same code
#Entity public class Person {
#ElementCollection
#CollectionTable(name="HOMES", joinColumns = #Column(name = "PERSON_ID"))
#Column(name="HOME_STATE")
protected List<String> vacationHomes;
...
}
Usinf Hibernate-jpa-2 version 1.0.0.Final
Deploy on JBoss 4.3.0.GA
And get exception (while deploying), that column HOME_STATE cann't be mapped on java.util.List
so I change List to ArrayList
After that application was deployed well.
But doesn't work well! I execute simple query, but annotations #ElementCollection and #CollectionTable were ignored! Working only #Column annotation
Can be problem with old JBoss version?
I don't know where problem...
Features that are part of JPA 2.0 are not working. That's because of missing implementation. In this case, only new annotations are there, but no processing (hibernate-jpa-2.0-api-1.0.0.Final is only JPA 2.0 interface, not the implementation).
According releases notes JBoss 4.3.0.GA was shipped with Hibernate 3.2.1, which is not JPA 2.0 implementation.
Making it work is next from impossible also with JBoss 5, as you can read from this question. If you cannot update at least to the JBoss 6.x, then it is easier to stick with JPA 1.

is mappedBy in hibernate defined as per schema definition or is it defined logically?

I have the following situation:
One Destination can have Many Aliases
Logically: I would like Destination to be the owner of this relationship, since if there was no destination, alias would not hold any meaning.
However, the database schema is like this:
DestinationAlias has idDestination as the Foreign Key and thus the #JoinColumn in hibernate annotation would be on DestinationAlias:
Destination:
#OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL}, mappedBy = "mainCity")
public Set<DestinationAlias> getAliases() {
return aliases;
}
DestinationAlias:
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDDESTINATION", nullable=false)
public Destination getMainCity() {
return mainCity;
}
From this definition, DestinationAlias is the owner of this relationship since the mappedBy is an attribute on Destination class.
Does hibernate require me to follow the database schema and mark entity as the owner of the relationship or can it be done based on Logical reasons ?
Ownership affects how hibernate would model the underlying database tables. If you omit the mappedBy attribute, hibernate would generate a join-table (like for an M-M relationship) between Destination and DestinationAlias, instead of a simple join column. Other than that, I'm curious as to what your actual issue is here. Is this purely cosmetic, or are there functional issues in play for you here?
EDIT: as this seems to be a purely cosmetic issue, my advice is to just accept the Hibernate semantic. While I agree that it might appear counter-intuitive that Hibernate would call DestinationAlias the "owner", that is just the nomenclature Hibernate decided on. It's not unique either and it comes from the notion that the "owner" is where the join-column resides.
Don't waste time trying to force hibernate to conform to your definitions when you don't have to.

Getting Javassist types instead of actual Hibernate entity types

I have stumbled upon a really annoying situation: I am using Hibernate & Spring as backend for my app and it seems that in some cases, the entities that are in a relationship with a particular entity are not fetched as normal entity objects from the DB, but as Javassist types. E.g.:
I have the Campaign entity with the following relationships:
#Entity
#Table(name = "campaign")
public class Campaign implements Serializable {
[..]
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(uniqueConstraints = #UniqueConstraint(columnNames = {
"campaign_id", "dealer_id" }), name = "campaign_has_dealer", joinColumns = { #JoinColumn(name = "campaign_id", nullable = false) }, inverseJoinColumns = { #JoinColumn(name = "dealer_id", nullable = false) })
private List<Dealer> dealers = new ArrayList<Dealer>();
#ManyToMany
// (fetch = FetchType.LAZY)
#JoinTable(uniqueConstraints = #UniqueConstraint(columnNames = {
"campaign_id", "sales_area_id" }), name = "campaign_has_sales_area", joinColumns = { #JoinColumn(name = "campaign_id", nullable = false) }, inverseJoinColumns = { #JoinColumn(name = "sales_area_id", nullable = false) })
private List<SalesArea> salesAreas = new ArrayList<SalesArea>();
}
Upon retrieving the salesAreas connected to this Campaign, I get a list of SalesArea_$$_javassist_56, while for the dealers, I get normal Hibernate entities. Since the client part is based on GWT, we use RequestFactory for retrieving stuff. I initially thought it was a problem with the proxies, locators and so on but I have set a breakpoint in the service where these are retrieved and they are Javassist objects directly after selecting them. It seems that even removing the FetchType.LAZY annotation (although definitely not a desirable solution), the same thing happens. This happened also with other types of relationships, not only #ManyToMany.
We are using GWT 2.3, Spring 3, Hibernate 3.6.3 and JPA 2.0 for annotations.
Any suggestions would be appreciated.
Thanks in advance
As far as I can see the big problem that you're having is not so much the fetch type of your association, but rather that the proxied types don't work well with RequestFactory.
Yes, it could be solved by changing the fetch strategy but that sounds rather like a weak workaround that may break upon weird circumstances.
I don't remember exactly how to solve it, but I did, and as far as I remember there was an extension point in the ServiceLayerDecorator class. Basically there you check if the object you're returning is a Hibernate proxy (check Hibernate and HibernateProxy classes) and then return the non-proxy type instead in ServiceLayerDecorator. (http://code.google.com/p/google-web-toolkit/issues/detail?id=6767)
As for your fetch strategy, I'd largely recommend #BatchSize(N) where N is big (maybe 1000), but this is an independent subject.
Good luck!
If you call to the static method:
HibernateProxyHelper.getClassWithoutInitializingProxy(entity);
you get the class of the proxied entity and the class itself if it wasn't proxied.
With Hibernate's proxy model and now with it's use of Javassist to help avoid the slower traditional Hibernate run time reflection operations things will never quite be as elegant as the clean, intuitive experience people who use full bytecode enhancement solutions like JDO implementations (eg DataNucleus) enjoy.
Personally I can never see the sense in persisting (pardon the pun) with solutions that cause so many problems and fill the web with questions about broken code that requires strange, unintuitive workarounds but still people do...
However, back to the question: one solution to your problem, if you're using JPA, is to use DataNucleus/JPA which brings many of the benefits of DataNucleus/JDO (clean underlying implementation - no proxies, no Javassist classes etc.,) in a JPA compliant implementation - i.e. you don't need to change your existing source code to start using it.

Categories

Resources