persistence@glassfish.java.net

Re: toplink/eclipselink explicit boolean mapping issue

From: Mitesh Meswani <Mitesh.Meswani_at_Sun.COM>
Date: Tue, 02 Jun 2009 00:33:39 -0700
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.