Thursday, 2 October 2014

Hibernate - annotation mappings and misleading SerializationException

Took me a few hours to get to the bottom of this.
I was getting the following Exception, which did not make sense as the deSerialization test passed OK.
org.springframework.orm.hibernate3.HibernateSystemException: could not deserialize; nested exception is org.hibernate.type.SerializationException: could not deserialize
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:692)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)

I have a domain object that I had proved through a unit test that I could serialize & deserialize successfully.

@Test
public void testDeserialize() throws Exception
{
CrmConfirmationReference srcRef = createConfirmationRef();
byte[] copy = SerializationUtils.serialize(srcRef);
CrmConfirmationReference deSerialized = (CrmConfirmationReference)SerializationUtils.deserialize(copy);
assertEquals("Oooops, not the same", srcRef), deSerialized);
}
view raw Unit test hosted with ❤ by GitHub

My domain object contained the following object which if I removed then worked OK:

@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
@JoinColumns({
@JoinColumn(name = "MPRN", nullable = false),
@JoinColumn(name = "EFFECTIVE_FROM", nullable = false)
})
@NotNull
public CrmMprn getMprn()
{
return mprn;
}

But tomcat & my integration test were both failing with the following Exception.

org.springframework.orm.hibernate3.HibernateSystemException: could not deserialize; nested exception is org.hibernate.type.SerializationException: could not deserialize
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:692)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:375)
at org.springframework.orm.hibernate3.HibernateTemplate.loadAll(HibernateTemplate.java:585)
at uk.co.utilisoft.crm350.dao.CrmGenericDao$1.doInHibernate(CrmGenericDao.java:82)
at uk.co.utilisoft.crm350.dao.CrmGenericDao$1.doInHibernate(CrmGenericDao.java:1)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:407)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
at uk.co.utilisoft.crm350.dao.CrmGenericDao.getAll(CrmGenericDao.java:78)
at uk.co.utilisoft.crm350.dao.CrmConfirmationReferenceIntegrationTest.testSerialize(CrmConfirmationReferenceIntegrationTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.type.SerializationException: could not deserialize
at org.hibernate.util.SerializationHelper.doDeserialize(SerializationHelper.java:262)
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:306)
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor.fromBytes(SerializableTypeDescriptor.java:130)
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor.wrap(SerializableTypeDescriptor.java:116)
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor.wrap(SerializableTypeDescriptor.java:39)
at org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor$2.doExtract(VarbinaryTypeDescriptor.java:62)
at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:64)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:249)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:229)
at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:330)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2283)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1527)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1455)
at org.hibernate.loader.Loader.getRow(Loader.java:1355)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:611)
at org.hibernate.loader.Loader.doQuery(Loader.java:829)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
at org.hibernate.loader.Loader.doList(Loader.java:2533)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
at org.hibernate.loader.Loader.list(Loader.java:2271)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)
at org.springframework.orm.hibernate3.HibernateTemplate$5.doInHibernate(HibernateTemplate.java:591)
at org.springframework.orm.hibernate3.HibernateTemplate$5.doInHibernate(HibernateTemplate.java:585)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:407)
... 36 more
Caused by: java.io.StreamCorruptedException: invalid stream header: 31323334
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:804)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at org.hibernate.util.SerializationHelper$CustomObjectInputStream.<init>(SerializationHelper.java:328)
view raw Stacktrace hosted with ❤ by GitHub

It turns out I had missed out an annotation, obvious really but I could not spot the error & the Exception was totally misleading. What had I missed? The '@manyToOne' annotation. Twit.

@ManyToOne(fetch = FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
@JoinColumns({
@JoinColumn(name = "MPRN", nullable = false),
@JoinColumn(name = "EFFECTIVE_FROM", nullable = false)
})
@NotNull
public CrmMprn getMprn()
{
return mprn;
}
view raw FullAnnotation hosted with ❤ by GitHub

4 comments:

Vance Blakely said...

Hey Bill, thanks very much for this post. I had the exact same issue and was totally confused by the error message that was produced.

After understanding the root cause of this issue, the error message does make a little more sense. It my case, the controller was failed to deserialize the object because of the missing annotation.

Once I added the ManyToOne annotation, everything work perfectly.

Thanks!

Unknown said...

Welcome Post very usefull informatation.and iam expecting more posts like this please keep updating us........

Unknown said...

I have the same Problem; however, it is strange: It does work well on Wildfly 8.2.1. Now I migrated to Wildfly 10.1.0. On my local PC, all works still fine; on OpenShift (same Wildfly Version, same Hibernate Version, ... same Project), this exception is raised, even though I pointed both instances to the same DB...
What can be wrong?
Why do you put the annotaion an the getter rather than on the field itself? Does this matter?
Thanks for your help.

Bill Comer said...

for the last Q - see https://stackoverflow.com/questions/305880/hibernate-annotation-placement-question

As to why, not sure. Firstly ensure you have a clean build. Secondly try reverting back to your 8.2.1 & verify it works again.