[
http://opensource.atlassian.com/projects/hibernate/browse/HHH-6313?page=c...
]
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