Showing posts with label Hibernate. Show all posts
Showing posts with label Hibernate. Show all posts

Thursday, February 26, 2009

Hibernate: QueryException: could not instantiate: (updated)

I was doing some queries today in EJB-QL on JBossAS (which uses Hibernate as persistence provider).
And for a query that was nicely working in the Jopr Gui, I got errors in the test suite:


javax.ejb.EJBTransactionRolledbackException: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not instantiate: com.acme.Foo
at ...... ( a lot ) ....
Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not instantiate: com.acme.Foo


Ok nice - Hibernate can not instantiate my class because it can not instantiate my class. So what?

After looking some time at this and debugging around I found out that the issue was the following. But before I show you the code, let me assure that IntelliJ flagged it as valid and it did work in the UI.

But now the code:


SELECT new com.acme.FOO(res.name, res.id, ... , parent.name, parent.id)

FROM Resource res

LEFT OUTER JOIN res.parentResource parent

...

WHERE ...


The constructor of com.acme.Foo looked like this:


Foo(String res.name, int res.id, ... , String parentName, int parentId) {}


This is all valid,

but:

It can happen for Resources at the root of the hierarchy to not have a parent (when they are roots). And in this case, parent is null and Hibernate is looking for a constructor to pass NULL in as last argument, which does not fit for 'int'. Thus the failure to instantiate the class.

The correct constrctor looks like this:

Foo(String res.name, int res.id, ... , String parentName, Integer parentId) {}

(of course you need to update the respective property within Foo too).

Conclusion:
Just to get it straight: Hibernate is doing the right thing - it's only not easy to find out what is going wrong.




Thursday, February 19, 2009

Postgres/Hibernate sql fun - NOT

This probably isn't really a postgres, but a more general issue, but then ...

I was writing some stuff in EJB-QL and all I got from Postgres was

ERROR: could not identify an ordering operator for type record
SQLState:42883

This sucks of course :)
After some trial and error I found the following in my query:

group by resource4_.NAME , ... , (measuremen1_.TIME, measuremen1_.ID)

Removing the parens ('(',')') finally made the query run successfully.

Now you may ask, what was the input that led to this? Well, here is is:

SELECT new Foo(a.id, b.id, ..., bla.id, bla.time)
FROM .... , org.acme.Bla bla
GROUP by a.id, b.id, bla

So the query translated the bla in the GROUP BY to (bla,id, bla.time) - including the parens. Explicitly listing bla.id, bla.time in the GROUP BY clause solved this.
This is no fun, as the EJB-QL Query got correctly translated and postgres does not give any hint, what part of this longish SQL it does not like.


Tuesday, February 19, 2008

Be careful with @OneToOne and lazy loading

When modelling an entity one sometimes wants to have information in a separate table even if it would exist only one time for a given entity. Think of a 1:0...1 composition. This could be handled as embedded in the primary entity, but perhaps you don't want to do this as the dependent object is huge and you don't always need it. The dependent table could even live in a different table space for that reason. Or just for relational normalization reasons.

For the @xxxToOne relations, JPA 1.0 spec sees Eager loading as default. One can give a *hint* that the dependend end should be lazily loaded, but this is only a hint.

Now when you have an optional @OneToOne relation, Hibernate (at least) needs to do an additional select for that relation to find out if the dependend object is null or not. For a mandatory (1..1) relation it can just install a proxy to lazily load the relation, but this is not possible for 1...0..1.
See e.g. http://www.hibernate.org/162.html for an explanation.

Friday, August 11, 2006

How to outsmart lazy loading

A customer recently had a problem with his O/R mapping framework(*) that all relations between objects/classes were marked to be loaded lazily. Despite this setting, loading a class (either by direct access or via HQL) caused all related classes to be loaded and their related ones as well until the whole graph of attached objects was in memory. The trace of the generated SQL clearly showed this behaviour without any explanation.

Looking at the mapping files, the queries or the java code for the relations brought not explanation. Also the startup of the mapper did not show any errors. The customer even implemented equals() and hashCode().

After having a closer look at the later two methods, the problem came clear: Hibernate did in deed only load the starting class and not the relations (initially). But when putting the entity into the Session, Hibernate has to call equals() or hashcode() for its internal maps. Those two methods now have been implemented my using (amongst other) some relation fields. So in order to compute the hashCode(), the relation had to be loaded (which in turn loaded the next relations, as the hashCode() method on the other classes were implemented in a similar manner).
So actually Hibernate worked as designed :-)

The use of collections within hashCode()/equals() is problematic anyway: a Map uses it to determine the location of the entry. If the hashcode changes this location is no longer correct, which will lead to strange problems.

As a summary: don't only be careful with externally generated primary keys within equals() and hashCode(), but also with using collections.


(*) Actually this was with Hibernate, but the problem can also arise with JDO, JPA etc.