persistence@glassfish.java.net

Re: toplink/eclipselink explicit boolean mapping issue

From: Prashant Dighe <Prashant.Dighe_at_Sun.COM>
Date: Tue, 02 Jun 2009 08:33:54 -0700

Hi Mitesh,

Thanks a lot for the workaround.

Hopefully this will not make any difference for other JPA providers and
other DBs, right?

Thanks,
Prashant

Mitesh Meswani wrote:
> Hi Prashant,
>
> Try running your test after changing the column name to upper case in
> orm.xml. That should move you forward
> <basic name="active">
> <column name="activeACTIVE"/>
> </basic>
>
> -Mitesh
>
> Prashant Dighe wrote:
>> Below are details of an issue that was troubling me for the last 2
>> days. Finally, I have a reproducible test case.
>>
>> Desperate for help :)
>>
>> Thanks in advance,
>> Prashant
>>
>>
>> Problem:
>> When a boolean type is explicitly mapped to a column, then exceptions
>> are thrown once a false value is written and you make a native query
>> call using a resultClass. Works as long as this column is never set
>> to false. Also works if the column has not been explicitly mapped.
>> Appears that the write causes things to go awry.
>>
>> JPA provider - TopLink-essentials OR EclipseLink (tried 1.0.1 as well
>> as 1.1.1)
>> Database - MySQL 5.1
>>
>> Table creation DDL,
>> CREATE TABLE `test`.`User`
>> (
>> id bigint NOT NULL AUTO_INCREMENT PRIMARY KEY,
>> firstName varchar(255),
>> lastName varchar(255),
>> age int,
>> wages double,
>> active tinyint
>> );
>>
>> In the orm mapping file (no annotations),
>> <basic name="active">
>> <column name="active"/>
>> </basic>
>>
>> The entity impl (UserModelImpl.class) has these methods,
>> public boolean isActive() {
>> return active;
>> }
>>
>> public void setActive(boolean active) {
>> this.active = active;
>> }
>>
>> public boolean getActive() {
>> return active;
>> }
>>
>>
>> Query 1:
>> Query query = em.createQuery("UPDATE UserModelImpl user SET
>> user.active = ?1 WHERE user.id = ?2");
>> query.setParameter(1, false);
>> query.setParameter(2, 3);
>> query.executeUpdate();
>>
>> Query 2:
>> String queryString = "select ID, FIRSTNAME, LASTNAME, AGE, WAGES,
>> ACTIVE from User";
>> Query query = em.createNativeQuery(queryString, UserModelImpl.class);
>> List list = query.getResultList();
>>
>>
>> Steps to reproduce:
>> Once you have executed Query 1 above, there onwards Query 2 will fail
>> with this exception.
>>
>> Exception [TOPLINK-33] (Oracle TopLink Essentials - 2.0 (Build
>> b41-beta2 (03/30/2007))):
>> oracle.toplink.essentials.exceptions.DescriptorException
>> Exception Description: Trying to invoke [setActive] on the object
>> [0]. The number of actual and formal parameters differs, or an
>> unwrapping conversion has failed.
>> Internal Exception: java.lang.IllegalArgumentException
>> Mapping:
>> oracle.toplink.essentials.mappings.DirectToFieldMapping[active-->User.active]
>> Descriptor: RelationalDescriptor(com.example.model.impl.UserModelImpl
>> --> [DatabaseTable(User)])
>>
>> oracle.toplink.essentials.exceptions.DescriptorException.illegalArgumentWhileSettingValueThruMethodAccessor(DescriptorException.java:634)
>>
>> oracle.toplink.essentials.internal.descriptors.MethodAttributeAccessor.setAttributeValueInObject(MethodAttributeAccessor.java:219)
>>
>> oracle.toplink.essentials.mappings.DatabaseMapping.setAttributeValueInObject(DatabaseMapping.java:1072)
>>
>> oracle.toplink.essentials.mappings.foundation.AbstractDirectMapping.buildCloneFromRow(AbstractDirectMapping.java:673)
>>
>> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildAttributesIntoWorkingCopyClone(ObjectBuilder.java:1089)
>>
>> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:1200)
>>
>> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:403)
>>
>> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:372)
>>
>> oracle.toplink.essentials.queryframework.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:371)
>>
>> oracle.toplink.essentials.queryframework.ObjectBuildingQuery.registerIndividualResult(ObjectBuildingQuery.java:303)
>>
>> oracle.toplink.essentials.queryframework.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:475)
>>
>> oracle.toplink.essentials.queryframework.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:310)
>>
>> oracle.toplink.essentials.queryframework.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:709)
>>
>> oracle.toplink.essentials.queryframework.DatabaseQuery.execute(DatabaseQuery.java:609)
>>
>> oracle.toplink.essentials.queryframework.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:677)
>>
>> oracle.toplink.essentials.queryframework.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:731)
>>
>> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2219)
>>
>> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:937)
>>
>> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:909)
>>
>> oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:346)
>>
>> oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.getResultList(EJBQueryImpl.java:453)
>>
>> When you debug the eclipselink code, it is actually passing 0 to the
>> setActive method. This happens with all the explicitly mapped boolean
>> types. If you remove the <column name="foo"/> from orm file then
>> everything works fine.
>>
>>