Hi all. First off let me say thanks for such a kickass product! I really love using Hibernate and I don't think I can ever go back to scattered SQL!
Relevant platform details:
Hibernate 2.1.2
Spring 1.0.1
jdk1.4.2
MySQL 4.0.16-standard
I'm having a problem with a custom identifier generator. I'm attempting to embed a native generator inside my custom generator so that most of the time the native generator gets called. There are, however, cases where I would like to use a pre-existing identifier (when I'm copying between different databases). The way I'm attemping to do this is by creating a native id generator (via a call to net.sf.hibernate.id.IdentifierGeneratorFactory) in the constructor of my custom IdentifierGenerator class. I want to use this native generator at all times except for the special case of copying between databases (and keeping the identifier consistent across multiple databases). However, when I attempt to use this native generator, I'm getting a MySQL driver error:
Code:
java.sql.SQLException: SQL String can not be NULL
.
I guess my questions are:
1) Is this possible, or do I need to think of another way to maintain ids between databases
2) If it is possible, what am I doing wrong?
The hibernate (spring) code is very simple -- I should mention that it works when I use a native id generator:
Code:
public void addAccessoryPage(MappedAccessoryPage page) {
getHibernateTemplate().save(page);
}
The generator is as follows:
Code:
public class PossiblyExistingIdGenerator implements IdentifierGenerator {
/**
* Use an IdentityGenerator if things are not set to be copied
*/
private IdentifierGenerator hibernateGenerator;
public PossiblyExistingIdGenerator() {
System.out.println("PossiblyExistingIdGenerator getting constructed \n\n");
try {
// Construction of native generator
hibernateGenerator = IdentifierGeneratorFactory.create("native", new LongType(), null, new MySQLDialect());
System.out.println("generator's class is: " + hibernateGenerator);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized Serializable generate(SessionImplementor session, Object object) {
if (object instanceof PersistentCopyable && ((PersistentCopyable) object).getCopiedIdentifier() != null) {
Long id = ((PersistentCopyable) object).getCopiedIdentifier();
System.out.println(" going to return: " + id);
return id;
} else {
try {
System.out.println(" going to call identity generator to generate new id ");
// Usage of native generator -- happens in most cases
Serializable returnValue = hibernateGenerator.generate(session, object);
System.out.println(" identity generator generated: " + returnValue);
return returnValue;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
}
My mapping document is as follows:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class
name="org.tolweb.hibernate.MappedAccessoryPage"
table="ACCESSORY_PAGES"
dynamic-update="false"
dynamic-insert="false"
>
<id
name="accessoryPageId"
column="id"
type="java.lang.Long"
unsaved-value="null"
>
<generator class="org.tolweb.hibernate.PossiblyExistingIdGenerator">
</generator>
</id>
<property
name="isSubmitted"
type="boolean"
update="true"
insert="true"
access="property"
column="is_submitted"
/>
<property
name="isTreehouse"
type="boolean"
update="true"
insert="true"
access="property"
column="is_treehouse"
/>
<property
name="menu"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="menu"
/>
<property
name="pageTitle"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="page_title"
/>
<property
name="copyright"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="page_copyrightholder"
/>
<property
name="copyrightYear"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="page_copyrightdate"
/>
<property
name="text"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="main_text"
/>
<property
name="references"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="refs"
/>
<property
name="status"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="status"
/>
<property
name="useContent"
type="boolean"
update="true"
insert="true"
access="property"
column="use_content"
/>
<set
name="contributors"
table="ACC_PAGE_CONTRIBUTORS"
lazy="false"
inverse="false"
cascade="none"
sort="natural"
order-by="page_order asc"
>
<key
column="page_id"
>
</key>
<composite-element
class="org.tolweb.treegrow.page.AccessoryPageContributor"
>
<property
name="order"
type="int"
update="true"
insert="true"
access="property"
column="page_order"
/>
<property
name="contributorId"
type="int"
update="true"
insert="true"
access="property"
column="contributor_id"
/>
<property
name="isAuthor"
type="boolean"
update="true"
insert="true"
access="property"
column="is_author"
/>
<property
name="isContact"
type="boolean"
update="true"
insert="true"
access="property"
column="is_contact"
/>
<property
name="isCopyOwner"
type="boolean"
update="true"
insert="true"
access="property"
column="is_copy_owner"
/>
</composite-element>
</set>
<set
name="internetLinks"
table="InternetLinks"
lazy="false"
inverse="false"
cascade="none"
sort="natural"
order-by="link_order asc"
>
<key
column="acc_page_id"
>
</key>
<composite-element
class="org.tolweb.treegrow.page.InternetLink"
>
<property
name="order"
type="int"
update="true"
insert="true"
access="property"
column="link_order"
/>
<property
name="comments"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="comments"
/>
<property
name="siteName"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="siteName"
/>
<property
name="url"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="url"
/>
</composite-element>
</set>
<set
name="nodesSet"
table="Acc_Pages_To_Nodes"
lazy="false"
inverse="false"
cascade="none"
sort="unsorted"
>
<key
column="acc_page_id"
>
</key>
<many-to-many
class="org.tolweb.hibernate.MappedNode"
column="node_id"
outer-join="auto"
/>
</set>
<property
name="contributorId"
type="int"
update="true"
insert="true"
access="property"
column="contributor_id"
/>
<property
name="usePermission"
type="byte"
update="true"
insert="true"
access="property"
column="use_permission"
/>
<property
name="acknowledgements"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="acknowledgements"
/>
<property
name="notes"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="notes"
/>
</class>
</hibernate-mapping>
Here's a more detailed debug log:
Code:
20:34:33,322 DEBUG SessionImpl:531 - opened session
going to call identity generator to generate new id
identity generator generated:
20:34:33,323 DEBUG SessionImpl:807 - saving [org.tolweb.hibernate.MappedAccessoryPage#<null>]
20:34:33,324 DEBUG SessionImpl:2273 - executing insertions
20:34:33,331 DEBUG EntityPersister:490 - Inserting entity: org.tolweb.hibernate.MappedAccessoryPage (native id)
20:34:33,332 DEBUG BatcherImpl:196 - about to open: 0 open PreparedStatements, 0 open ResultSets
20:34:33,391 DEBUG SQL:237 -
Hibernate: null
20:34:33,391 DEBUG BatcherImpl:241 - preparing statement
Here's the exception:
Code:
20:34:33,391 DEBUG BatcherImpl:241 - preparing statement
java.sql.SQLException: SQL String can not be NULL
at com.mysql.jdbc.PreparedStatement.<init>(PreparedStatement.java:109)
at com.mysql.jdbc.Connection.prepareStatement(Connection.java:1358)
at com.mysql.jdbc.Connection.prepareStatement(Connection.java:1293)
at com.mysql.jdbc.Connection.prepareStatement(Connection.java:1393)
at com.p6spy.engine.spy.P6Connection.prepareStatement(P6Connection.java:287)
at org.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:370)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:415)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at net.sf.hibernate.util.GetGeneratedKeysHelper.prepareStatement(GetGeneratedKeysHelper.java:39)
at net.sf.hibernate.impl.BatcherImpl.getPreparedStatement(BatcherImpl.java:246)
at net.sf.hibernate.impl.BatcherImpl.prepareStatement(BatcherImpl.java:61)
at net.sf.hibernate.persister.EntityPersister.insert(EntityPersister.java:524)
at net.sf.hibernate.persister.EntityPersister.insert(EntityPersister.java:432)
at net.sf.hibernate.impl.ScheduledIdentityInsertion.execute(ScheduledIdentityInsertion.java:29)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:906)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:839)
at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:757)
at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:720)
at org.springframework.orm.hibernate.HibernateTemplate$8.doInHibernate(HibernateTemplate.java:242)
at org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:150)
at org.springframework.orm.hibernate.HibernateTemplate.save(HibernateTemplate.java:240)
at org.tolweb.dao.AccessoryPageDAOImpl.addAccessoryPage(AccessoryPageDAOImpl.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.springframework.aop.framework.AopProxyUtils.invokeJoinpointUsingReflection(AopProxyUtils.java:59)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:138)
at $Proxy3.addAccessoryPage(Unknown Source)
at org.tolweb.dao.AccessoryPageDAOTest.testFieldsMatching(AccessoryPageDAOTest.java:165)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:289)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.executeInVM(JUnitTask.java:954)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.execute(JUnitTask.java:626)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.execute(JUnitTask.java:600)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:269)
at org.apache.tools.ant.Task.perform(Task.java:364)
at org.apache.tools.ant.Target.execute(Target.java:301)
at org.apache.tools.ant.Target.performTasks(Target.java:328)
at org.apache.tools.ant.Project.executeTarget(Project.java:1215)
at org.apache.tools.ant.Project.executeTargets(Project.java:1063)
at org.apache.tools.ant.Main.runBuild(Main.java:632)
at org.apache.tools.ant.Main.startAnt(Main.java:183)
at org.apache.tools.ant.launch.Launcher.run(Launcher.java:197)
at org.apache.tools.ant.launch.Launcher.main(Launcher.java:56)