persistence@glassfish.java.net

toplink/eclipselink explicit boolean mapping issue

From: Prashant Dighe <Prashant.Dighe_at_Sun.COM>
Date: Mon, 01 Jun 2009 11:53:47 -0700

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.