TaintedString is my own custom class that just wrapps String and deprecates toString(). I've told Hibernate to treat each varchar or text column as a TaintedString in the .hbm.xml files, but I haven't told Hibernate HOW to actually turn a varchar into a TaintedString. How do I do that? Implement org.hibernate.persister.entity.Loadable? Do I need to provide an org.hibernate.persister.entity.EntityPersister?
Here's some of UserSession.hbm.xml:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Jul 6, 2012 2:33:02 PM by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class name="myApp.db.UserSession" table="user_session" catalog="my_app">
<id name="id" type="long">
<column name="id" />
<generator class="identity" />
</id>
<property name="sessionIdStr" type="myApp.util.TaintedString">
<column name="session_id_str" length="32" not-null="true">
<comment>request.getSession().getId()</comment>
</column>
</property>
Here's some of my persistent UserSession.java class:
Code:
public class UserSession implements java.io.Serializable {
private static final long serialVersionUID = 20130917213740L;
private long id;
private TaintedString sessionIdStr;
/** default constructor */
public UserSession() {
}
public long getId() { return id; }
public void setId(long x) { id = x; }
public TaintedString getSessionIdStr() { return sessionIdStr; }
public void setSessionIdStr(TaintedString x) { sessionIdStr = x; }
Here's some of TaintedString.java - the wrapper for String:
Code:
public class TaintedString implements Comparable<TaintedString>, Serializable {
private static final long serialVersionUID = 20130917223500L;
private final String s;
private TaintedString(String str) { s = str; }
public static TaintedString of(String str) {
if (str == null) {
return null;
}
return new TaintedString(str);
}
...
And when I try to run, I get this exception:
Code:
org.hibernate.type.SerializationException: could not deserialize
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:217)
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:240)
at org.hibernate.type.SerializableType.fromBytes(SerializableType.java:82)
at org.hibernate.type.SerializableType.get(SerializableType.java:39)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:154)
at org.hibernate.type.AbstractType.hydrate(AbstractType.java:81)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2101)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1380)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1308)
at org.hibernate.loader.Loader.getRow(Loader.java:1206)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:580)
at org.hibernate.loader.Loader.doQuery(Loader.java:701)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1860)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:48)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:42)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3049)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:399)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:375)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:139)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:195)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:103)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:815)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:808)
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.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
at com.sun.proxy.$Proxy4.get(Unknown Source)
at planbase.hoshin.util.HibernateUtil.get(HibernateUtil.java:167)
at planbase.hoshin.db.UserSession.getUSessFromCookies(UserSession.java:396)
at planbase.hoshin.servlet.HoshinActionServlet.process(HoshinActionServlet.java:347)
at planbase.hoshin.servlet.HoshinActionServlet.doGet(HoshinActionServlet.java:264)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at planbase.hoshin.filters.UTF8Filter.doFilter(UTF8Filter.java:23)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.io.StreamCorruptedException: invalid stream header: 33344343
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:802)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at org.hibernate.util.SerializationHelper$CustomObjectInputStream.<init>(SerializationHelper.java:252)
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:209)
... 56 more
Hibernate has been working great for me in production for 6 years now. Since it worked before this change, looks to me like Hibernate expect to my custom string wrapper class in serialized form in the database. But the data is just stored in varchar and/or text fields as raw strings, not serialized java.lang.String objects, and certainly not as myApp.util.TaintedString objects. When Hibernate tries to deserialize it, java.io.ObjectInputStream wants the first two shorts to be some special secret Java serialization code that regular strings in the database don't start with. They are just raw strings.
So I think that I need Hibernate to know how to construct my class from a plain JDBC String. How do I let Hibernate know 1. that it needs to do that and 2. how to do that?