I am trying to implement the Hstore-Datatype and use it in JPA Entities. However, when I try to persist some testdata, I get several errors.
For implementing the Hstore-Datatype I used the following tutorial: Storing Sets of Key/value Pairs in a Single Db Column With Hibernate Using PostgreSQL Hstore Type
This is the code, which I have right now in my application:
A helper for converting a Map to a String conforming to hstore syntax and vice versa:
public class HstoreHelper {
private static final String K_V_SEPARATOR = "=>";
public static String toString(Map<String, String> m) {
if (m.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
int n = m.size();
for (String key : m.keySet()) {
sb.append("\"" + key + "\"" + K_V_SEPARATOR + "\"" + m.get(key) + "\"");
if (n > 1) {
sb.append(", ");
n--;
}
}
return sb.toString();
}
public static Map<String, String> toMap(String s) {
Map<String, String> m = new HashMap<String, String>();
if (s.isEmpty()) {
return m;
}
String[] tokens = s.split(", ");
for (String token : tokens) {
String[] kv = token.split(K_V_SEPARATOR);
String k = kv[0];
k = k.trim().substring(1, k.length() - 1);
String v = kv[1];
v = v.trim().substring(1, v.length() - 1);
m.put(k, v);
}
return m;
}
}
A UserType implementation:
public class HstoreUserType implements UserType {
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}
public Object deepCopy(Object o) throws HibernateException {
Map m = (Map) o;
return new HashMap(m);
}
public Serializable disassemble(Object o) throws HibernateException {
return (Serializable) o;
}
public boolean equals(Object o1, Object o2) throws HibernateException {
Map m1 = (Map) o1;
Map m2 = (Map) o2;
return m1.equals(m2);
}
public int hashCode(Object o) throws HibernateException {
return o.hashCode();
}
public boolean isMutable() {
return true;
}
public Object nullSafeGet(ResultSet rs, String[] strings, Object o)
throws HibernateException, SQLException {
String col = strings[0];
String val = rs.getString(col);
return HstoreHelper.toMap(val);
}
public void nullSafeSet(PreparedStatement ps, Object obj, int i)
throws HibernateException, SQLException {
String s = HstoreHelper.toString((Map) obj);
ps.setObject(i, s, Types.OTHER);
}
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
public Class returnedClass() {
return Map.class;
}
public int[] sqlTypes() {
return new int[] { Types.INTEGER };
}
}
And using it in an entity bean:
@Entity
@TypeDef(name = "hstore", typeClass = HstoreUserType.class)
@XmlRootElement
@Table(name = "address")
public class Address {
.
.
.
@Type(type = "hstore")
@Column(columnDefinition = "hstore")
private Map<String, String> hs = new HashMap<String, String>();
.
.
.
}
I tried to publish the application with the instances of address, but these errors appear:
14:40:47,906 INFO [stdout] (MSC service thread 1-1) Hibernate: insert into address (housenumber, location, street, zipcode, address_id) values (?, ?, ?, ?, ?)
14:40:47,921 WARN [com.arjuna.ats.arjuna] (MSC service thread 1-1) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffff0a49215c:-6aa8b5cf:53b3d0e3:133, org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization@628b66 >: java.lang.AbstractMethodError
at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:155) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
14:40:48,062 INFO [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] (MSC service thread 1-1) HHH000010: On release of batch it still contained JDBC statements
14:40:48,093 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-1) MSC00001: Failed to start service jboss.deployment.unit."ductbased.war".component.TestDataGenerator.START: org.jboss.msc.service.StartException in service jboss.deployment.unit."ductbased.war".component.TestDataGenerator.START: Failed to start service
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1767) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
14:40:49,265 ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 2) {"JBAS014653: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"JBAS014671: Failed services" => {"jboss.deployment.unit.\"ductbased.war\".component.TestDataGenerator.START" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"ductbased.war\".component.TestDataGenerator.START: Failed to start service"}}}}
Could someone please tell me, why the error appears? The author of the tutorial claims, that the code works for him, so I'm left alone a bit :D And it is also the first time, I implement an own datatype. Thank you in advance!