How to manage XmlType on H2 database
I use H2 Database for my unit tests.
In my application, I have an Entity object called FooXml
defined like that:
@Entity
@Table(name = "T_FOOXML")
@SequenceGenerator(allocationSize = 1, name = "S_FOOXML", sequenceName = "S_FOOXML")
@NamedQueries( ... )
@Cache(usage = CacheConcurrencyStrategy.NONE)
public class FooXml implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "S_FOOXML")
@Column(name = "FOOXML_ID")
private Integer id;
@Type(type = "my.app.common.HibernateXMLType")
@Column(name = "FOOXML_CONTENT")
@Basic(fetch = FetchType.LAZY)
private String xmlContent;
...
}
So in order to read / write the XML content from the Database, I have created my own XMLType, my.app.common.HibernateXMLType
, which implements org.hibernate.usertype.UserType
.
The methods nullSafeSet
and nullSafeGet
are defined there.
Now, I want to use a H2 in-memory Database for my tests, and some tests are using this FooXml
class.
As H2 does not support The Oracle XmlType
, I have to customize my my.app.common.HibernateXMLType
.
For example, I added that part:
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
...
// Case where H2 Database is used as the dataSource...
if (st.getConnection() instanceof org.h2.jdbc.JdbcConnection) {
// Set the XML as a String...
st.setObject(index, (String) value);
} else {
// Case of "normal" behavior (outside tests context)
...
}
}
I have several concerns with this approach:
- I add code that is directly linked to tests purpose in the production code of the application (i.e. not in the test code);
- As this class depends on
org.h2.jdbc.JdbcConnection
, I have to add the h2-database dependency in my WAR package.
Questions:
- Is it the best approach to solve my problem, or is there a better way of doing that?
- Is there a way to tell Hibernate to use another Type (
my.app.common.HibernateXMLTypeForH2
instead ofmy.app.common.HibernateXMLType
) for tests purpose?
ps : The script for creating my table in开发者_StackOverflow H2 database is the following:
create table T_FOO_XML (
FOOXML_ID NUMBER(9, 0) not null,
FOOXML_CONTENT CLOB(400000)
);
Technical details: H2 Database v1.3.153, JUnit 4.8.1, Java 1.6, Hibernate 3.2.2, Oracle 10g is used in none-test environments.
I add code that is directly linked to tests purpose in the production code...
In a way, yes, because you use H2 for testing. However, you could argue you make your application more database independent, and using H2 for testing only is only a coincidence. Later on, you could use H2 as the database shipped with the trial version of your product. Or you could support other databases in addition to Oracle and H2 later on.
h2-database dependency
To avoid the compile-time dependency on H2, you could use:
String url = st.getConnection().getMetaData().getURL();
boolean isH2 = url.startsWith("jdbc:h2:");
if (isH2) {
...
}
There are other ways, for example getMetaData().getDatabaseProductName().equals("H2")
- basically compare with a String instead of Class objects. Of course that's not as compile-time safe, on the other hand H2 might return a different connection class in the future, so JdbcConnection
is also unstable.
public class Oracle10gDialectWithXMLType extends Oracle10gDialect {
public Oracle10gDialectWithXMLType() {
registerHibernateType(XMLType._SQL_TYPECODE, "XMLTYPE");
registerColumnType(XMLType._SQL_TYPECODE, "XMLTYPE");
}
}
and add it as ur dialect in properties.
精彩评论