[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-6313) ClassCastException specifying type="character" in hbm.xml

Tom Jordahl (JIRA) noreply at atlassian.com
Tue Aug 9 14:47:02 EDT 2011


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-6313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=43203#comment-43203 ] 

Tom Jordahl commented on HHH-6313:
----------------------------------

Here is a test case to reproduces the issue.

DB Schema for Table Person (HSQL syntax):
CREATE TABLE PEOPLEPERSON(PERSONID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,FIRSTNAME VARCHAR(255),LASTNAME VARCHAR(255),SEX CHAR(1)

Query query = session.createQuery("select Person_alias from Person Person_alias where Person_alias.sex = :sex");
query.setParameter("sex", "M");
result = query.list();

Hibernate 3.5 was loose enough to convert the String parameter of length 1 to a Character if and when it was needed.  The 3.6 problem comes from the code in VarcharTypeDescriptor.java (actually the overridden doBind() function), which wants to convert what it thinks is a Character type to a string:
VarcharTypeDescriptor.java: ~line 52
  st.setString( index, javaTypeDescriptor.unwrap( value, String.class, options ) ); 

In this instance, the "value" type is String, and the "javaTypeDescriptor" is an instance of CharacterTypeDescriptor, which has the following signature for unwrap():
CharacterTypeDescriptor.java: ~line 54
	public <X> X unwrap(Character value, Class<X> type, WrapperOptions options) {

The class cast come from the VM as a String "value" is passed in to this function, and the signature expects a Character.

Arguably this is "user error" because I am passing in an incorrect type (String) for a query parameter that should be a Character.  I would say that this should be fixed for the following reasons:
- This is breaking backwards compatibility, 3.5 worked.  3.6 doesn't.
- This is a very common "mistake" made by users
- The system has more than enough information to do the right thing here.  When the query parameters are constructed, the NamedParameterDescriptor class has the expectedType and should be able to convert the "value" passed in to doBind() to this expected type.  

As an alternative, the code that tries to bind the string parameter can detect if the "value" is already of the correct type and NOT call unwrap().  As an example:
CharacterTypeDescriptor.java: ~line 54
  if (value instanceof String)
      st.setString( index, value ); 
  else
      st.setString( index, javaTypeDescriptor.unwrap( value, String.class, options ) );


In our system, we do not have the type information for the query parameters available to us, so as a workaround here is user code that will detect this situation and convert the query param to the right type:

query.setParameter(paramName, paramValue);
if (paramValue instanceof String && ((String) paramValue).length() == 1)
{
    // Work around Hibernate bug https://hibernate.onjira.com/browse/HHH-6313
    // Hibernate 3.5 allowed Strings for character type arguments, 3.6+ is more strict.
    if (query instanceof QueryImpl)
    {
        Type t = ((QueryImpl) query).getParameterMetadata().getNamedParameterExpectedType(paramName);
        if (t.getName().equals(CharacterType.INSTANCE.getName()))
        {
            query.setCharacter(paramName,((String) paramValue).charAt(0));
        }
    }
}

This code isn't so great, as it has to drop down to QueryImpl to get the job done, but it does work around the issue.

Hibernate developer thoughts welcome!



> ClassCastException specifying type="character" in hbm.xml
> ---------------------------------------------------------
>
>                 Key: HHH-6313
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-6313
>             Project: Hibernate Core
>          Issue Type: Bug
>    Affects Versions: 3.6.0, 3.6.4, 3.6.5
>         Environment: Hibernate 3.6.5, Oracle 10g
>            Reporter: Martin
>
> I have a class containing a field of type java.lang.Character.
> I map this to an Oracle char(1 byte) field using an hmb.xml file as follows:
> <property name="IntroducedFlag" column="INTRODUCED" type="character" />
> At runtime this results in the following exception:
> java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Character
>  at org.hibernate.type.descriptor.java.CharacterTypeDescriptor.unwrap(CharacterTypeDescriptor.java:34)
>  at org.hibernate.type.descriptor.sql.VarcharTypeDescriptor$1.doBind(VarcharTypeDescriptor.java:52)
>  at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:91)
>  at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:282)
>  at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:277)
>  at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1873)
>  at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1844)
>  at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1716)
>  at org.hibernate.loader.Loader.doQuery(Loader.java:801)
>  at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
>  at org.hibernate.loader.Loader.doList(Loader.java:2533)
>  at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
>  at org.hibernate.loader.Loader.list(Loader.java:2271)
>  at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119)
>  at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716)
>  at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)
> It works fine in Hibernate 3.5.6 but not in 3.6.0 onwards.
> Also probably related to this issue:
> https://forum.hibernate.org/viewtopic.php?f=1&t=1010175

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list