Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    ClassCastException if field name of related Datasource clashes with own field name

    Hello,

    there seems to be a bug in the Hibernate Datsource if the field name of an entity is equals to a field name of a related entity. (I currently evaluating the 3.1d enterprise edition (2012/10/04).

    the code is like this:

    Code:
    @Entity
    public class ShippingMethod implements Serializable {
    
    	@Id
    	private String id;
    
    	@AttributeOverride(name = "defaultValue", column = @Column(name = "name", length = 50))
    	@Embedded
    	private Translatable name;
    
    	@ManyToOne(fetch = FetchType.LAZY, optional = false)
    	private Site site;
    	
    	/* getter + setter */
    }
    Code:
    package test.server;
    
    import javax.persistence.AttributeOverride;
    import javax.persistence.Column;
    import javax.persistence.Embedded;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.Id;
    import javax.persistence.ManyToOne;
    import java.io.Serializable;
    
    @Entity
    public class ShippingMethod implements Serializable {
    
    	@Id
    	private String id;
    
    	@AttributeOverride(name = "defaultValue", column = @Column(name = "name", length = 50))
    	@Embedded
    	private Translatable name;
    
    	@ManyToOne(fetch = FetchType.LAZY, optional = false)
    	private Site site;
    	
    	/* getter + setter */
    }
    Code:
    package test.server;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import java.io.Serializable;
    import java.util.Collection;
    
    @Entity
    public class Site implements Serializable {
    
    	@Id
    	private String name;
    
    	@OneToMany(mappedBy = "site", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    	private Collection<ShippingMethod> shippingMethods;
    	
    	/* getter + setter */
    }
    Code:
    package test.server;
    
    import javax.persistence.Access;
    import javax.persistence.AccessType;
    import javax.persistence.Embeddable;
    
    @Embeddable
    @Access(AccessType.FIELD)
    public class Translatable {
    	private String defaultValue;
    	
    	/* getter + setter */
    }
    Code:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <DataSource
            ID="shippingMethod"
            serverType="hibernate"
            dropExtraFields="true"
            beanClassName="test.server.ShippingMethod">
        <fields>
            <field name="id" type="text" primaryKey="true"/>
            <field name="name" type="text" valueXPath="/name/defaultValue"/>
            <field name="site" required="true" canEdit="true" foreignKey="site.name" displayField="site_name"/>
            <field name="site_name" type="text" valueXPath="site/name" canEdit="false" canSave="false" hidden="true"/>
        </fields>
    </DataSource>
    Code:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <DataSource ID="site"
                serverType="hibernate"
                dropExtraFields="true"
                beanClassName="test.server.Site">
        <fields>
            <field name="name" type="text" primaryKey="true"/>
        </fields>
    </DataSource>
    Code:
    package test.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.types.ListGridComponent;
    import com.smartgwt.client.widgets.events.ClickEvent;
    import com.smartgwt.client.widgets.events.ClickHandler;
    import com.smartgwt.client.widgets.form.fields.SelectItem;
    import com.smartgwt.client.widgets.grid.ListGrid;
    import com.smartgwt.client.widgets.grid.ListGridField;
    import com.smartgwt.client.widgets.layout.HLayout;
    import com.smartgwt.client.widgets.toolbar.ToolStrip;
    import com.smartgwt.client.widgets.toolbar.ToolStripButton;
    
    public class Entry implements EntryPoint {
    
    	public void onModuleLoad() {
    		DataSource siteDs = DataSource.get("site");
    
    		final ListGrid siteGrid = new ListGrid();
    		siteGrid.setDataSource(siteDs);
    		initGrid(siteGrid);
    
    		final ListGrid shippingMethodGrid = new ListGrid();
    		shippingMethodGrid.setDataSource(DataSource.get("shippingMethod"));
    
    		SelectItem selectItem = new SelectItem("site");
    		selectItem.setOptionDataSource(siteDs);
    		selectItem.setDisplayField("name");
    		selectItem.setValueField(siteDs.getPrimaryKeyFieldName());
    
    		ListGridField infoListGridField = new ListGridField("site");
    		infoListGridField.setEditorType(selectItem);
    		shippingMethodGrid.setFields(infoListGridField);
    
    		initGrid(shippingMethodGrid);
    
    		HLayout mainLayout = new HLayout();
    		mainLayout.setWidth100();
    		mainLayout.setHeight100();
    		mainLayout.addMember(siteGrid);
    		mainLayout.addMember(shippingMethodGrid);
    
    		mainLayout.draw();
    
    	}
    
    	private void initGrid(final ListGrid grid) {
    		grid.setAutoFetchData(true);
    		grid.setAutoSaveEdits(false);
    		grid.setCanEdit(true);
    		grid.setUseAllDataSourceFields(true);
    
    
    		ToolStrip strip = new ToolStrip();
    		ToolStripButton save = new ToolStripButton("save");
    		save.addClickHandler(new ClickHandler() {
    			@Override
    			public void onClick(ClickEvent clickEvent) {
    				grid.saveAllEdits();
    			}
    		});
    		strip.addButton(save);
    		ToolStripButton add = new ToolStripButton("add");
    		add.addClickHandler(new ClickHandler() {
    			@Override
    			public void onClick(ClickEvent clickEvent) {
    				grid.startEditingNew();
    			}
    		});
    		strip.addButton(add);
    		grid.setGridComponents(ListGridComponent.HEADER, ListGridComponent.BODY, strip);
    	}
    }
    Now you create 2 sites and one ShippingMethod. After this you change the Site of the ShippingMethod (update). Now you get this warning:

    Code:
    === 2012-10-10 01:47:04,919 [70-1] WARN  HibernateDataSource - [builtinApplication.shippingMethod_update] java.lang.IllegalArgumentException: Can't convert value of type java.lang.String to target type test.server.Translatable
    The data in the example is updated correctly, but under certain circumstances, which I could not yet identify, you get the following warning:

    Code:
    =!= 2012-10-10 01:34:36,258 [sor3] WARN  DataSource - [builtinApplication.shippingMethod_update] Couldn't set property 'site' for datasource 'shippingMethod'. Actual error: java.lang.ClassCastException: test.servern.Translatable cannot be cast to java.lang.String
    in this case no update is commited to the Database. I could extract the following StackTrace for this Exception:

    Code:
    java.lang.ClassCastException: test.server.Translatable cannot be cast to java.lang.String
    	at org.hibernate.type.descriptor.java.StringTypeDescriptor.unwrap(StringTypeDescriptor.java:38)
    	at org.hibernate.type.descriptor.sql.VarcharTypeDescriptor$1.doBind(VarcharTypeDescriptor.java:57)
    	at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:92)
    	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:305)
    	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:300)
    	at org.hibernate.param.NamedParameterSpecification.bind(NamedParameterSpecification.java:66)
    	at org.hibernate.loader.hql.QueryLoader.bindParameterValues(QueryLoader.java:588)
    	at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1736)
    	at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1697)
    	at org.hibernate.loader.Loader.doQuery(Loader.java:832)
    	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:293)
    	at org.hibernate.loader.Loader.doList(Loader.java:2382)
    	at org.hibernate.loader.Loader.doList(Loader.java:2368)
    	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2198)
    	at org.hibernate.loader.Loader.list(Loader.java:2193)
    	at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470)
    	at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355)
    	at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:195)
    	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1244)
    	at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
    	at com.isomorphic.hibernate.HibernateDataSource.setRelationFieldValue(HibernateDataSource.java:5945)
    	at com.isomorphic.datasource.DataSource.setProperties(DataSource.java:1629)
    	at com.isomorphic.datasource.DataSource.setProperties(DataSource.java:1582)
    	at com.isomorphic.hibernate.HibernateDataSource.processRequest(HibernateDataSource.java:1433)
    	at com.isomorphic.hibernate.HibernateDataSource.executeUpdate(HibernateDataSource.java:805)
    	at com.isomorphic.datasource.DataSource.execute(DataSource.java:1384)
    	at com.isomorphic.application.AppBase.executeDefaultDSOperation(AppBase.java:726)
    	at com.isomorphic.application.AppBase.executeAppOperation(AppBase.java:658)
    	at com.isomorphic.application.AppBase.execute(AppBase.java:491)
    	at com.isomorphic.datasource.DSRequest.execute(DSRequest.java:2011)
    Stepping throught the stack shows that the HibernateDatasource is trying to set a parameter of type test.server.Translatable for the query

    Code:
    select __Site from test.server.Site __Site where __Site.name = :p0
    This seems to be a bug.

    #2
    Hi,

    Thanks for spotting.
    I've committed changes.
    You will be able to get it with nightly build 2012-10-11.

    Regards,
    Alius

    Comment


      #3
      Hello,

      I can confirm, that the bug is fixed also for the 2nd usecase (the one I couldn't reproduce in the example code above).

      Thanks for fixing it!

      Comment

      Working...
      X