/**
* @ejb.persistence column-name="NAZWA" jdbc-type="BLOB"
*/
public abstract String getNazwa();
Atrybut jest typu String, więc spodziewałem się że w bazie będą zapisane po prostu ciągi bajtów uzyskane metodą getBytes(). Jednak po sprawdzeniu istniejących wartości okazało się, że są to zserializowane obiekty i to nie klasy String, ale org.jboss.invocation.MarshalledValue (aplikacja działa na JBossie). Konieczne było więc napisanie odpowiedniej implementacji Hibernate'owego interfejsu UserType. Pomocny okazał się - jakże by inaczej - Spring, dostarczając bazowej klasy AbstractLobType:
public class MarshalledStringType extends AbstractLobType {
private static final int[] TYPES = { Types.BLOB };
protected Object nullSafeGetInternal(
ResultSet rs, String[] names,
Object owner, LobHandler lobHandler)
throws SQLException, IOException, HibernateException {
if (names.length != 1) {
throw new HibernateException("invalid column names");
}
Blob blob = rs.getBlob(names[0]);
try {
ObjectInputStream ois = new ObjectInputStream(blob.getBinaryStream());
MarshalledValue mv = (MarshalledValue) ois.readObject();
return mv.get();
} catch (IOException e) {
throw new HibernateException(e);
} catch (ClassNotFoundException e) {
throw new HibernateException(e);
}
}
protected void nullSafeSetInternal(
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException, IOException, HibernateException {
MarshalledValue mv = new MarshalledValue(value);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(mv);
oos.close();
baos.close();
lobCreator.setBlobAsBytes(ps, index, baos.toByteArray());
}
public Class returnedClass() {
return String.class;
}
public int[] sqlTypes() {
return TYPES;
}
}
Aby nowy typ był widoczny dla Hibernate wystarczy jedna adnotacja, najlepiej w pliku package-info.java w pakiecie nadrzędnym dla klas modelu danych:
@org.hibernate.annotations.TypeDefs({
@org.hibernate.annotations.TypeDef(
name = "marshalledString",
typeClass = MarshalledStringType.class
)
})
package pakiet.nadrzedny.modelu.danych;
Od tego momentu marshalledString może być używany tak samo jak wszystkie standardowe typy dostępne w Hibernate:
@Basic
@Type(type = "marshalledString")
@Column(name = "NAZWA")
public String getNazwa() {
return nazwa;
}
Brak komentarzy
Prześlij komentarz