-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Fail to use select new MyClass(...) from .... in some cases
PostPosted: Wed Mar 23, 2005 10:21 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
Hibernate version:3.0

When I use the following query:

select myObj.name, count(*), Min(myObj.data), Max(myObj.date) from MyObjectClass myObj ....

I get an array of Object, everything is fine.
I can even check that I get an array of object and the first onject is of type String,
the second of type Integer and the last 2 of type Timestamp.

The following query is working just fine as well:
select new MyClass(myObj.name, ... , myObj.date) from MyObjectClass myObj ....

MyClass class having the right constructor


Now when I try the following query:

select new MyClass(myObj.name, ... , count(*), Min(myObj.data), Max(myObj.date)) from MyObjectClass myObj ....

I get 2 types of errors depending on the constructor:

if the constructor is
public MyClass(String name, Object numberOfItem, Object dateFrom, Object dateUntil) {...}

I get the error "could not instantiate: class MyClass"

if the constructor is
public MyClass(String name, Integer numberOfItem, Timestamp dateFrom, Timestamp dateUntil) {...}

I get the error "org.hibernate.PropertyNotFoundException: no appropriate constructor in class: MyClass"

My problem starts when I have aggregate functions. Is there any restriction in the use of typesafe Java object
in the query?
Any hint is welcome.

Thanks,

Richard


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 6:53 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
there shouldnt be.

-max

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 3:09 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
Hi Max,

My understanding also was that there should not be any problem, but somehow I'm having trouble with this.

When I don't use any aggregate function, everything is fine.

The code I use is:

String queryStr = "select new MyClass(myObj.data) from MyObject myObj where ...";
Query query = session.createQuery(queryStr);
List result = query.list();

public class MyClass implements Serializable {

private String data = null;

public MyClass() {
}

public MyClass(String data) {
this.data = data;
}

// Getters and Setters
...


Now if I do the following:

String queryStr = "select new MyClass(myObj.data, count(*)) from MyObject myObj where ...";
Query query = session.createQuery(queryStr);
List result = query.list();

public class MyClass implements Serializable {

private String data = null;
private Integer count = null;

public MyClass() {
}

public MyClass(String data, Integer count) {
this.data = data;
this.count = count;
}

// Getters and Setters
...

I get the error: "could not instantiate: class MyClass"

When I do the following:

String queryStr = "select new MyClass(myObj.data, min(myObj.stamp)) from MyObject myObj where ...";
Query query = session.createQuery(queryStr);
List result = query.list();

public class MyClass implements Serializable {

private String data = null;
private Timestamp startDate = null;

public MyClass() {
}

public MyClass(String data, Timestamp startDate) {
this.data = data;
this.startDate = startDate;
}

// Getters and Setters
...

I get the error: "could not instantiate: class MyClass"

Now if I have 2 aggregate functions
String queryStr = "select new MyClass(myObj.data, count(*), min(myObj.stamp)) from MyObject myObj where ...";
Query query = session.createQuery(queryStr);
List result = query.list();

public class MyClass implements Serializable {

private String data = null;
private Integer count = null;
private Timestamp startDate = null;

public MyClass() {
}

public MyClass(String data, Integer count, Timestamp startDate) {
this.data = data;
this.count = count;
this.startDate = startDate;
}

// Getters and Setters
...


I get a different error: "no appropriate constructor in class: MyClass"

So somehow something goes wrong somewhere when using aggregate function. there is not much about using "select new MyClass..."
in hibernate online doc or in HIA since it is a pretty straighforward feature.

I removed the "new MyClass" to get the array of object so that I could check the type of the values returned by count(*) and
min(myObj.stamp) and make sure I had the appropriate constructor.

I will start looking in Hibernate code to find where the problem happen and try to understand what is the problem.
Meanwhile if someone ran into a similar problem or if someone see what is wrong with my code, I'm be gald to hear from you.

Richard


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 3:43 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
what is the stacktrace of those errors ?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 5:14 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
O tried to debug a little and the problem occurs in the following method of the org.hibernate.util.ReflectHelper class:
public static Constructor getConstructor(Class clazz, Type[] types)

For some reason, the number of element in types is much more than the number of argument than my constructor. Therefore there is no macth for an appropriate constructor and a PropertyNotFoundException is thrown.


Here is the stacktrace:
(com.securimine.common.beans.grouping.CustomGroupingItemRow is MyClass in the previous post).


org.hibernate.PropertyNotFoundException: no appropriate constructor in class: co
m.securimine.common.beans.grouping.CustomGroupingItemRow
at org.hibernate.util.ReflectHelper.getConstructor(ReflectHelper.java:22
5)
at org.hibernate.hql.classic.QueryTranslatorImpl.renderSQL(QueryTranslat
orImpl.java:581)
at org.hibernate.hql.classic.QueryTranslatorImpl.compile(QueryTranslator
Impl.java:179)
at org.hibernate.hql.classic.QueryTranslatorImpl.compile(QueryTranslator
Impl.java:151)
at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.jav
a:414)
at org.hibernate.impl.SessionImpl.getQueries(SessionImpl.java:814)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:773)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:74)
at com.securimine.server.grouping.dbiterator.GroupingDynamicIterator.ini
t(GroupingDynamicIterator.java:127)
at com.securimine.server.common.dbiterator.ModuleIteratorA.<init>(Module
IteratorA.java:60)
at com.securimine.server.grouping.dbiterator.GroupingDynamicIterator.<in
it>(GroupingDynamicIterator.java:51)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstruct
orAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingC
onstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
at com.securimine.client.common.util.ViewIteratorFactory.getIterator(Vie
wIteratorFactory.java:74)
at com.securimine.client.common.action.ViewMainAction.execute(ViewMainAc
tion.java:92)
at org.apache.struts.action.RequestProcessor.processActionPerform(Reques
tProcessor.java:421)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.ja
va:226)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:116
4)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:397)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl
icationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF
ilterChain.java:157)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperV
alve.java:214)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValv
eContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.jav
a:520)
at org.apache.catalina.core.StandardContextValve.invokeInternal(Standard
ContextValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextV
alve.java:152)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValv
eContext.java:104)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(Authentica
torBase.java:540)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValv
eContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.jav
a:520)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.j
ava:137)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValv
eContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.j
ava:118)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValv
eContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.jav
a:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineVal
ve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValv
eContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.jav
a:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)

at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:16
0)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java
:799)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.proce
ssConnection(Http11Protocol.java:705)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java
:577)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadP
ool.java:683)
at java.lang.Thread.run(Thread.java:534)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 5:45 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
After debuging a little more, I found there is a strange behaviour is the
org.hibernate.hql.classic.QuerytranslatorImpl.renderSQL() method

line 581:
ReflectHelper.getConstructor( holderClass, returnTypes ) is called

returnTypes has an increasing number of values when it is called.
It is not reset properly (or maybe not reset at all).
When I got into that method first, returnTypes had 10 values (where it should have been only 5. Looking at the values, it seems I have twice the set of values expected).
Then when I go again in that method, I get 15 values into returnTypes.

I will keep investigate further.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 6:42 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
Please, disregard my last post. This behaviour seems to be caused by the debugger.
returnTypes has the right number of objects.

In public static Constructor getConstructor(Class clazz, Type[] types) method
of the org.hibernate.util.ReflectHelper class, the code tries to find the right constructor.

One one end types contains 7 objects:
org.hibernate.type.StringType
org.hibernate.type.IntegerType
org.hibernate.type.StringType
org.hibernate.type.IntegerType
org.hibernate.type.IntegerType (this is for count(*) )
org.hibernate.type.TimestampType (this is for min(myObj.stamp) )
org.hibernate.type.TimestampType (this is for max(myObj.stamp) )

so far so good.

Then the method tries to find the right constructor. to do so, it compares the number
of paramters. When a constructor with the same number of parameters is found, then each parameter
is compared against the objects in the variable types.

The Class[] params is that case contains 7 objects:
java.lang.String
java.lang.Integer
java.lang.String
java.lang.Integer
java.lang.Integer
java.sql.Timestamp
java.sql.Timestamp

For each of this objects, the method tries to find out if they are compatible by evaluating the following:
final boolean ok = params[j].isAssignableFrom( types[j].getReturnedClass() ) || (
types[j] instanceof PrimitiveType &&
params[j] == ( (PrimitiveType) types[j] ).getPrimitiveClass());


For StringType and IntegerType, params[j].isAssignableFrom( types[j].getReturnedClass() ) is true
so the first 5 parameters are fine.
But for TimestampType, params[j].isAssignableFrom( types[j].getReturnedClass() ) return false as well as
types[j] instanceof PrimitiveType. Therefore the all expression is false and the PropertyNotFoundException
is thrown.

I think that using the aggregate function should work fine with other type (like Integer, String,...).
Only in the case of Timestamp, this is an issue.

It seems it is a hibernate bug then. I don't know if it is known issue.
I'll try to find out.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 7:30 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
im quite sure that returntypes is the correct size (otherwise the junit testcases would fail on this)

are you sure you didnt rerun the method via a debugger one to many times.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 7:34 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
Yes the returntypes size is fine (debugger problem).
I found out that the issue was comparing the compatibility of parameters types with the return types of the query in case of Timestamp.

here is in short what I said in the previous posts. Sorry for the confusion.

select new MyClass(myObj.id,..., min(myObj.stamp)) from MyObject myObj ... throws a
PropertyNotFoundException in the method
public static Constructor getConstructor(Class clazz, Type[] types)
of the org.hibernate.util.ReflectHelper class.
when min(...) return a value of type timestamp (other types seems to work fine)

In that method, the code
final boolean ok = params[j].isAssignableFrom( types[j].getReturnedClass() ) || (
types[j] instanceof PrimitiveType &&
params[j] == ( (PrimitiveType) types[j] ).getPrimitiveClass());
return false when types[j] = org.hibernate.type.TimestampType and params[j] = java.sql.Timestamp

In that case:
params[j].isAssignableFrom( types[j].getReturnedClass() ) is evaluated to false
and
types[j] instanceof PrimitiveType is also evaluated to false
making the all expression false and therefore throwing a PropertyNotFoundException.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 7:44 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
what concrete class is that Timestamp ?

I would almost bet you that it is not a java.sql.Timestamp but something driver specfic which actually is not assignable since it was loaded by a different classloader (namely the drivers classloader)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 7:49 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
we have seen it before - again timestamp and classloader issues.


http://forum.hibernate.org/viewtopic.ph ... p&start=15

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 7:52 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
It is a java.sql.Timestamp.

Here is the mapping file:
<hibernate-mapping>

<class name="RepositoryEvent" table="SECRepositoryEvent">

<id name="id" type="java.lang.Long" column="id">
<generator class="increment"/>
</id>

<property name="stamp" type="java.sql.Timestamp" column="stamp" not-null="true"/>
...

This is the stamp value that min(myObj.stamp) will return.

The class I use for in the "select new ..." define also the value as java.sql.Timestamp


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 7:55 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
but what classloader does it come from ?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 8:05 pm 
Beginner
Beginner

Joined: Thu Jan 06, 2005 6:21 pm
Posts: 23
I have the jdbc driver jtds-1.0.2.jar under $CATALINA_HOME$\common\lib only.
So it should be fine, right?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 24, 2005 8:13 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
well no - since that classloader is next to hibernate, not the parent of hibernate (i assume)

try to run this as a standalone tests within a plain main() method and tell me if it works-fails.

_________________
Max
Don't forget to rate


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.