You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by "Meeks, Andrew" <an...@vt.edu> on 2017/12/05 16:00:44 UTC

Cayenne 4.1 DataRow and objEntity with java.lang.Boolean

I have recently migrated from 4.0 to 4.1.  I have a few instances where I perform a query and then I create an instance of my entity from the resulting DataRow.  These object entities have both Integer and Boolean fields.  DataRow has always cast these fields as BigDecimal.

In 4.0 the DataContext.objectFromDataRow handled these fields, evidently because CayenneDataObject could put BigDecimal into the values map of <String, Object>.

In 4.1 it appears as though each entity implements its own writePropertyDirectly which puts the object into a typed field of that entity.  The objectFromDataRow fails because of the cast exception from BigDecimal to Boolean or BigDecimal to Integer.  So these fields evidently need to be converted to correct types before being set on the entity.

My workaround is to write a utility method that cleans up the DataRow before I hand it to objectFromDataRow.  The utility method looks for any attributes that are BigDecimal on the DataRow, then for the same field name in the entity, it looks for the desired type.  Then it does an appropriate conversion from BigDecimal.

        public static void cleanUpDataRow(DataContext dContext, Class clazz, DataRow dataRow) {
               ObjEntity entity = dContext.getEntityResolver().getObjEntity(clazz);
               Collection<ObjAttribute> entityAttributes = entity.getAttributes();
               for(ObjAttribute attribute : entityAttributes) {
                       String attributeClass = attribute.getType();
                       if(dataRow.get(attribute.getDbAttributeName()) != null &&
                         dataRow.get(attribute.getDbAttributeName()).getClass().getTypeName().equals("java.math.BigDecimal")) {
                              if(attributeClass.equals("java.lang.Boolean")) {
                                      dataRow.put(attribute.getDbAttributeName(), (dataRow.get(attribute.getDbAttributeName()).equals(BigDecimal.valueOf(1))));
                              } else if(attributeClass.equals("java.lang.Integer")) {
                                      dataRow.put(attribute.getDbAttributeName(), ((BigDecimal)dataRow.get(attribute.getDbAttributeName())).intValue());
                              }
                       }
               }
        }

Usage:

...
CayennePatch.cleanUpDataRow(dContext, ROrganizationalChart.class, dataRow);
ROrganizationalChart fetchedChart = dataContext.objectFromDataRow(ROrganizationalChart.class, dataRow);
...

How can I use DataRows in 4.1 with objectFromDataRow without using a custom method?
Thank you!
Andrew


RE: Cayenne 4.1 DataRow and objEntity with java.lang.Boolean

Posted by "Meeks, Andrew" <an...@vt.edu>.
Thank you, yes, I am using SQLSelect but I had not made use of the #result directive.  I shall do so!

Andrew

-----Original Message-----
From: Andrus Adamchik [mailto:andrus@objectstyle.org] 
Sent: Wednesday, December 06, 2017 4:23 PM
To: user@cayenne.apache.org
Subject: Re: Cayenne 4.1 DataRow and objEntity with java.lang.Boolean

Hi Andrew,

What is the origin of the DataRows? If they come from a SQLSelect/SQLTemplate query, there's a way to control value types with #result directive [1]. This will fix the issue in 4.1, and is arguably the best approach even in 4.0, as loading values of incorrect type to a DataObject via a generic API only defers a ClassCastException, not prevents it entirely.

Cheers,
Andrus

[1] https://cayenne.apache.org/docs/4.0/cayenne-guide/queries.html#sqltemplate


> On Dec 5, 2017, at 11:00 AM, Meeks, Andrew <an...@vt.edu> wrote:
> 
> I have recently migrated from 4.0 to 4.1.  I have a few instances where I perform a query and then I create an instance of my entity from the resulting DataRow.  These object entities have both Integer and Boolean fields.  DataRow has always cast these fields as BigDecimal.
> 
> In 4.0 the DataContext.objectFromDataRow handled these fields, evidently because CayenneDataObject could put BigDecimal into the values map of <String, Object>.
> 
> In 4.1 it appears as though each entity implements its own writePropertyDirectly which puts the object into a typed field of that entity.  The objectFromDataRow fails because of the cast exception from BigDecimal to Boolean or BigDecimal to Integer.  So these fields evidently need to be converted to correct types before being set on the entity.
> 
> My workaround is to write a utility method that cleans up the DataRow before I hand it to objectFromDataRow.  The utility method looks for any attributes that are BigDecimal on the DataRow, then for the same field name in the entity, it looks for the desired type.  Then it does an appropriate conversion from BigDecimal.
> 
>        public static void cleanUpDataRow(DataContext dContext, Class clazz, DataRow dataRow) {
>               ObjEntity entity = dContext.getEntityResolver().getObjEntity(clazz);
>               Collection<ObjAttribute> entityAttributes = entity.getAttributes();
>               for(ObjAttribute attribute : entityAttributes) {
>                       String attributeClass = attribute.getType();
>                       if(dataRow.get(attribute.getDbAttributeName()) != null &&
>                         dataRow.get(attribute.getDbAttributeName()).getClass().getTypeName().equals("java.math.BigDecimal")) {
>                              if(attributeClass.equals("java.lang.Boolean")) {
>                                      dataRow.put(attribute.getDbAttributeName(), (dataRow.get(attribute.getDbAttributeName()).equals(BigDecimal.valueOf(1))));
>                              } else if(attributeClass.equals("java.lang.Integer")) {
>                                      dataRow.put(attribute.getDbAttributeName(), ((BigDecimal)dataRow.get(attribute.getDbAttributeName())).intValue());
>                              }
>                       }
>               }
>        }
> 
> Usage:
> 
> ...
> CayennePatch.cleanUpDataRow(dContext, ROrganizationalChart.class, 
> dataRow); ROrganizationalChart fetchedChart = 
> dataContext.objectFromDataRow(ROrganizationalChart.class, dataRow); ...
> 
> How can I use DataRows in 4.1 with objectFromDataRow without using a custom method?
> Thank you!
> Andrew
> 


Re: Cayenne 4.1 DataRow and objEntity with java.lang.Boolean

Posted by Andrus Adamchik <an...@objectstyle.org>.
Hi Andrew,

What is the origin of the DataRows? If they come from a SQLSelect/SQLTemplate query, there's a way to control value types with #result directive [1]. This will fix the issue in 4.1, and is arguably the best approach even in 4.0, as loading values of incorrect type to a DataObject via a generic API only defers a ClassCastException, not prevents it entirely.

Cheers,
Andrus

[1] https://cayenne.apache.org/docs/4.0/cayenne-guide/queries.html#sqltemplate


> On Dec 5, 2017, at 11:00 AM, Meeks, Andrew <an...@vt.edu> wrote:
> 
> I have recently migrated from 4.0 to 4.1.  I have a few instances where I perform a query and then I create an instance of my entity from the resulting DataRow.  These object entities have both Integer and Boolean fields.  DataRow has always cast these fields as BigDecimal.
> 
> In 4.0 the DataContext.objectFromDataRow handled these fields, evidently because CayenneDataObject could put BigDecimal into the values map of <String, Object>.
> 
> In 4.1 it appears as though each entity implements its own writePropertyDirectly which puts the object into a typed field of that entity.  The objectFromDataRow fails because of the cast exception from BigDecimal to Boolean or BigDecimal to Integer.  So these fields evidently need to be converted to correct types before being set on the entity.
> 
> My workaround is to write a utility method that cleans up the DataRow before I hand it to objectFromDataRow.  The utility method looks for any attributes that are BigDecimal on the DataRow, then for the same field name in the entity, it looks for the desired type.  Then it does an appropriate conversion from BigDecimal.
> 
>        public static void cleanUpDataRow(DataContext dContext, Class clazz, DataRow dataRow) {
>               ObjEntity entity = dContext.getEntityResolver().getObjEntity(clazz);
>               Collection<ObjAttribute> entityAttributes = entity.getAttributes();
>               for(ObjAttribute attribute : entityAttributes) {
>                       String attributeClass = attribute.getType();
>                       if(dataRow.get(attribute.getDbAttributeName()) != null &&
>                         dataRow.get(attribute.getDbAttributeName()).getClass().getTypeName().equals("java.math.BigDecimal")) {
>                              if(attributeClass.equals("java.lang.Boolean")) {
>                                      dataRow.put(attribute.getDbAttributeName(), (dataRow.get(attribute.getDbAttributeName()).equals(BigDecimal.valueOf(1))));
>                              } else if(attributeClass.equals("java.lang.Integer")) {
>                                      dataRow.put(attribute.getDbAttributeName(), ((BigDecimal)dataRow.get(attribute.getDbAttributeName())).intValue());
>                              }
>                       }
>               }
>        }
> 
> Usage:
> 
> ...
> CayennePatch.cleanUpDataRow(dContext, ROrganizationalChart.class, dataRow);
> ROrganizationalChart fetchedChart = dataContext.objectFromDataRow(ROrganizationalChart.class, dataRow);
> ...
> 
> How can I use DataRows in 4.1 with objectFromDataRow without using a custom method?
> Thank you!
> Andrew
>