We're updating the issue view to help you get more done. 

java.util.Calendar conversion to java.util.Date fails

Description

When using java.util.Calendar in a query to retrieve an entity class containing a field of java.util.Date type it throws exceptions.

1 2 3 4 5 6 Caused by: java.lang.IllegalArgumentException: Parameter value [java.util.GregorianCalendar[time=1382561831603,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-21600000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2013,MONTH=9,WEEK_OF_YEAR=43,WEEK_OF_MONTH=4,DAY_OF_MONTH=23,DAY_OF_YEAR=296,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=3,HOUR_OF_DAY=15,MINUTE=57,SECOND=11,MILLISECOND=603,ZONE_OFFSET=-21600000,DST_OFFSET=3600000]] did not match expected type [java.util.Date] at org.hibernate.ejb.AbstractQueryImpl.validateParameterBinding(AbstractQueryImpl.java:375) [hibernate-entitymanager-4.2.0.SP1-redhat-1.jar:4.2.0.SP1-redhat-1] at org.hibernate.ejb.AbstractQueryImpl.registerParameterBinding(AbstractQueryImpl.java:348) [hibernate-entitymanager-4.2.0.SP1-redhat-1.jar:4.2.0.SP1-redhat-1] at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:419) [hibernate-entitymanager-4.2.0.SP1-redhat-1.jar:4.2.0.SP1-redhat-1] at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:73) [hibernate-entitymanager-4.2.0.SP1-redhat-1.jar:4.2.0.SP1-redhat-1] at org.jboss.as.jpa.container.QueryNonTxInvocationDetacher.setParameter(QueryNonTxInvocationDetacher.java:142) [jboss-as-jpa-7.2.1.Final-redhat-10.jar:7.2.1.Final-redhat-10]

The same code worked fine in EAP 5 with Hibernate 3.
Here are the code snippets:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // With GregorianCalendar the execution failed in EAP6.1, but NOT in EAP5! // GregorianCalendar date = new GregorianCalendar(); // With Date the execution successes in EAP6.1! Date date = new Date(); Query query = this.manager.createQuery("from xxx where maketime <= :_maketime"); query.setParameter("_maketime", date, TemporalType.TIMESTAMP); return query.getResultList(); @Entity public class xxx implements Serializable { ... private Date maketime; public Date getMaketime() { return maketime; } public void setMaketime(Date maketime) { this.maketime = maketime; } }

I've checked the hibernate source code.
In hibernate-entitymanager-3.4.0.GA-CP04(eap 5.1.2), I find the following code that seems to allow both java.util.Date and java.util.Calendar to work.
org.hibernate.ejb.QueryImpl.java:
public Query setParameter(String name, Date value, TemporalType temporalType);
public Query setParameter(String name, Calendar value, TemporalType temporalType);
The similar code still exists in hibernate-entitymanager-4.2.0.SP1-redhat-1 in org.hibernate.ejb.QueryImpl. However, it adds call to
registerParameterBinding( getParameter(name), value );
which in turns calls
private void validateParameterBinding(Parameter parameter, Object value)
in org.hibernate.ejb.AbstractQueryImpl:

1 2 3 4 5 6 7 8 9 10 11 12 13 private void validateParameterBinding(Parameter parameter, Object value) { if ( value == null || parameter.getParameterType() == null ) { // nothing we can check return; } if ( Collection.class.isInstance( value ) && ! Collection.class.isAssignableFrom( parameter.getParameterType() ) ) { // we have a collection passed in where we are expecting a non-collection. // NOTE : this can happen in Hibernate's notion of "parameter list" binding // NOTE2 : the case of a collection value and an expected collection (if that can even happen) // will fall through to the main check. validateCollectionValuedParameterMultiBinding( parameter, (Collection) value ); } else if ( value.getClass().isArray() ) { validateArrayValuedParameterBinding( parameter, value ); } else { if ( ! parameter.getParameterType().isInstance( value ) ) { throw new IllegalArgumentException( String.format( "Parameter value [%s] did not match expected type [%s]", value, parameter.getParameterType().getName() ) ); } } }

Is this the expected behavior? Any reason we make such change?
I've also checked the JPA spec 2.0. It doesn't mention that java.util.Calendar should work with java.util.Date field or vice visa. It only mentions that the java.util.Date and java.util.Calendar should be supported for TemporalType.TIMESTAMP in "11.1.47 Temporal Annotation".

Environment

None

Status

Assignee

Brett Meyer

Reporter

Gary Hu

Fix versions

Labels

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Affects versions

4.2.0.Final

Priority

Major