I'm currently working on a GWT + Hibernate project which should work together on an already defined and filled database. I receive an
com.google.gwt.user.client.rpc.SerializationException
when I query the database.
Here are my objects...
Database:
-- Table: asset
CREATE TABLE IF NOT EXISTS asset
(
isin VARCHAR(12) NOT NULL,
mic_code VARCHAR(4) NOT NULL DEFAULT 'n.a.',
name VARCHAR(255) NOT NULL,
type_id VARCHAR(36) NOT NULL,
PRIMARY KEY (isin, mic_code),
INDEX(isin, mic_code),
FOREIGN KEY (type_id) REFERENCES asset_type(id)
)ENGINE=InnoDB;
-- Table: asset_type
CREATE TABLE IF NOT EXISTS asset_type
(
id VARCHAR(36) NOT NULL,
type VARCHAR(40) NOT NULL,
PRIMARY KEY (id)
)ENGINE=InnoDB;
Asset.java:
public class Asset implements Serializable {
private String isin;
private String mic_code;
private String name;
private AssetType assetType;
public Asset() {
super();
}
...
AssetType.java
public class AssetType implements Serializable {
private String id;
private String type;
public AssetType() {
}
and finally the hibernate xml files: Asset.hbm.xml
<hibernate-mapping>
<class name="com.mygwtproject.shared.model.Asset" table="ASSET">
<id name="isin" type="java.lang.String" access="field">
<column name="ISIN" />
<generator class="native" />
</id>
<property name="mic_code" type="java.lang.String" access="field">
<column name="MIC_CODE" />
</property>
<property name="name" type="java.lang.String" access="field">
<column name="NAME" />
</property>
<many-to-one name="assetType" class="com.mygwtproject.shared.model.types.AssetType" column="TYPE_ID" cascade="all" not-null="true"/>
</class>
</hibernate-mapping>
AssetType.hbm.xml
<hibernate-mapping>
<class name="com.mygwtproject.shared.model.types.AssetType" table="ASSET_TYPE">
<id name="id" type="java.lang.String" column="ID">
<generator class="native" />
</id>
<property name="type" type="java.lang.String" column ="TYPE" />
</class>
</hibernate-mapping>
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">*****</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/asset_db</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="use_sql_comments">true</property>
<mapping resource="com/mygwtproject/shared/model/Asset.hbm.xml" />
<mapping resource="com/mygwtproject/shared/model/types/AssetType.hbm.xml" />
</session-factory>
</hibernate-configuration>
from log:
Hibernate:
select
assettype0_.ID as ID1_1_0_,
assettype0_.TYPE as TYPE2_1_0_
from
ASSET_TYPE assettype0_
where
assettype0_.ID=?
09:43:09,139 TRACE BasicBinder:81 - binding parameter [1] as [VARCHAR] - [ee5bb49a-dc95-403a-9f77-864a9c342f25]
09:43:09,142 TRACE BasicExtractor:78 - extracted value ([TYPE2_1_0_] : [VARCHAR]) - [Stock]
Starting Jetty on port 8888
[WARN] Exception while dispatching incoming RPC call
com.google.gwt.user.client.rpc.SerializationException: Type 'com.mygwtproject.shared.model.types.AssetType_$$_jvst77c_0' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.: instance = com.mygwtproject.shared.model.types.AssetType@7d617ac9
so there is something wrong with my Asset -> AssetType mapping, but i cant find it. Any help is appreciated. thanks
edit:
mysql> select * from asset_type where id = 'ee5bb49a-dc95-403a-9f77-864a9c342f25';
returns
+--------------------------------------+-------+
| id | type |
+--------------------------------------+-------+
| ee5bb49a-dc95-403a-9f77-864a9c342f25 | Stock |
+--------------------------------------+-------+
1 row in set (0.00 sec)
Solution from here:
1. Create counterpart Data Transfer Objects and replace the hibernate objects.
AssetDTO.java
public class AssetDTO implements Serializable {
private String isin;
private String mic_code;
private String name;
private AssetTypeDTO assetType;
public AssetDTO() {
super();
}
public AssetDTO(String isin, String mic_code, String name,
AssetTypeDTO assetType) {
super();
this.isin = isin;
this.mic_code = mic_code;
this.name = name;
this.assetType = assetType;
}
//incl. Getter + Setter
}
AssetTypeDTO.java
public class AssetTypeDTO implements Serializable {
private String id;
private String type;
public AssetTypeDTO() {
super();
}
public AssetTypeDTO(String id, String type) {
super();
this.id = id;
this.type = type;
}
//incl. Getter + Setter
}
2. Add a new constructor to the hibernate objects.
Asset.java
...
public Asset(AssetDTO dto) {
this.isin = dto.getIsin();
this.mic_code = dto.getMic_code();
this.name = dto.getName();
AssetTypeDTO assetTypeDTO = dto.getAssetType();
if (assetTypeDTO != null) {
this.assetType = new AssetType(assetTypeDTO.getId(),
assetTypeDTO.getType());
}
}
...
AssetType.java
public AssetType(AssetTypeDTO dto) {
this.id = dto.getId();
this.type = dto.getType();
}
3. Modify your GWT RPC components. Replace the Hibernate objects in
IService.java
public List<Asset> getAssets();
with the DTOs.
public List<AssetDTO> getAssets();
IServiceAsync.java
public void getAssets(AsyncCallback<List<Asset>> callback);
with
public void getAssets(AsyncCallback<List<AssetDTO>> callback);
4. Modify your service implementation.
ServiceImpl.java
...
@Override
public List<AssetDTO> getAssets() {
...
Query q = session.createQuery("from Asset");
List<Asset> assets = new ArrayList<Asset>(q.list());
List<AssetDTO> assetsDto = new ArrayList<AssetDTO>();
if (assets != null) {
for (Asset asset : assets) {
assetsDto.add(createAssetDTO(asset));
}
}
session.getTransaction().commit();
return assetsDto;
}
public AssetDTO createAssetDTO(Asset asset) {
AssetTypeDTO assetTypeDto = new AssetTypeDTO(asset.getAssetType()
.getId(), asset.getAssetType().getType());
AssetDTO result = new AssetDTO(asset.getIsin(), asset.getMicCode(),
asset.getName(), assetTypeDto);
return result;
}
...
5. Move the Hibernate objects (Asset, AssetType) to the server
package, move the DTOs (AssetDTO, AssetTypeDTO) to the shared
package and update the path in your Hibernate xml files.