I'm looking into working around an issue related to Oracle DATE data types and java.sql.Timestamp bind values, which are applied by Hibernate (or pretty much any other database API, such as jOOQ) by default for timestamp information. The Oracle issue is documented here:
With Hibernate, I can either use the proprietary UserType API (explained in the first article), or I should be able to use JPA 2.1 converters to force an oracle.sql.DATE bind value, which also helps circumventing the original issue:
import java.sql.Timestamp;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import oracle.sql.DATE;
@Converter
public class OracleDateConverter
implements AttributeConverter<Timestamp, DATE>{
@Override
public DATE convertToDatabaseColumn(Timestamp attribute) {
return attribute == null ? null : new DATE(attribute);
}
@Override
public Timestamp convertToEntityAttribute(DATE dbData) {
return dbData == null ? null : dbData.timestampValue();
}
}
Unfortunately, Hibernate treats all Serializable types as VARBINARY as can be seen here:
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) {
return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor );
}
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
st.setObject( index, value, jdbcTypeCode );
}
};
}
I think this is a bit too clever on the Hibernate side. If I wanted that behaviour, I can still implement a AttributeConverter<Timestamp, byte[]> and implement the three lines of serialisation code myself.
However, by defaulting to VARBINARY inside of Hibernate, I'm deprived of using a lot of vendor-specific JDBC types, such as this one INTERVAL types, or TIMESTAMPTZ, or all the various PostgreSQL PGobject, PGgeometry, PGbox, PGcircle, or even simple array types, which I don't want to be Java-serialized, but simply passed through to the server via PreparedStatement.setObject().
Note that this behaviour is not at all specified in AttributeConverter
|