Alex
Alex Coding pays my food bills

Fixing createClob is not yet implemented error in Spring Boot 2


Fixing createClob is not yet implemented error in Spring Boot 2

You’ve just upgraded to Spring Boot 2.x, excited to try out the reactive support in Spring Framework 5 or just benefit from the significant library improvements. You start up your trusty postgres backed microservice, but to your horror you look at console and see it’s filled up with a stackstrace!

1
2
3
Caused by: java.sql.SQLFeatureNotSupportedException: Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented.
	at org.postgresql.Driver.notImplemented(Driver.java:688) ~[postgresql-42.2.5.jar:42.2.5]
	at org.postgresql.jdbc.PgConnection.createClob(PgConnection.java:1269) ~[postgresql-42.2.5.jar:42.2.5]

What’s going on here? Is Spring Boot 2 not compatible with postgres? You breathe a sigh of relief when Spring finishes booting up, everything seems ok. You learn to live with the stack strace but all the time wondering what causes this and how do it get rid of it.

Looking at the stack trace it is clear that the original exception originated postgresql jdbc driver. It turns out that Postgresql doesn’t support the Clob data type, the JDBC interface expects any implementing driver to be able to create a Clob or throw java.sql.SQLFeatureNotSupportedException, which is exactly what Postgresql JDBC does. On startup the Hibernate bootstrap does not know the capabilities of underlaying JDBC driver, so Hibernate must query the driver by reflecting on the java.sql.Connection class method to check if a SQLFeatureNotSupportedException is thrown.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Taken from org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl
final Class connectionClass = Connection.class;
final Method createClobMethod = connectionClass.getMethod( "createClob", NO_ARG_SIG );
if ( createClobMethod.getDeclaringClass().equals( Connection.class ) ) {
    // If we get here we are running in a jdk 1.6 (jdbc 4) environment...
    // Further check to make sure the driver actually implements the LOB creation methods.  We
    // check against createClob() as indicative of all; should we check against all 3 explicitly?
    try {
        final Object clob = createClobMethod.invoke( jdbcConnection, NO_ARGS );
        try {
            final Method freeMethod = clob.getClass().getMethod( "free", NO_ARG_SIG );
            freeMethod.invoke( clob, NO_ARGS );
        }
        catch ( Throwable ignore ) {
            LOG.tracef( "Unable to free CLOB created to test createClob() implementation : %s", ignore );
        }
        return true;
    }
    catch ( Throwable t ) {
        LOG.disablingContextualLOBCreationSinceCreateClobFailed( t );
    }

Now the real root cause of the issue is the last line above logging that the create clob method cannot be called LOG.disablingContextualLOBCreationSinceCreateClobFailed(t). Running the exact same setup but using Spring Boot 1.5.21 the error printed out to the console by disablingContextualLOBCreationSinceCreateClobFailed is:

1
2019-06-16 18:57:43.818  INFO 49885 --- [           main] o.h.e.j.e.i.LobCreatorBuilderImpl        : HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException

Much cleaner…

So it would seem that our culprit is in a logging implementation detail.

Crisis Averted

Phew! At least this is not going to break anything, it’s just going to be a pain in butt everytime you look at the application logs. I don’t know about you, but I don’t want that happening. The quickest and easiest to prevent the stack strace appearing is to add the following to your application.properties file:

1
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

This property prevents hibernate from querying the JDBC for Clob information, and if it doesn’t query the driver then the stack strace won’t be produced. It is also possible to use an undocumented feature within Hibernate to disable jdbc metadata defaults, but be warned the database dialect must be manually set as Hibernate will not longer attempt to detect the dialect.

1
2
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL95Dialect

I see no reason to use this method over the one above, I’ve just put it here for reference.

The proper solution to this will be the fix in the Hibernate Core library see (HHH-12368). This fix will be released in the Hibernate Core 5.4.x releases, but at the time of writing (16/06/19) Spring Boot 2.1.5 is not currently using this version (it uses 5.3.10.FINAL), but once the fix is incorporated in the Spring Boot release this issue will be no more.

tl;dr: Add spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true to the application.properties file to make the error disappear or use Hibernate Core 5.4.x and above. NOTE: The latest Spring Boot 2.1.5 (as of 16/06/19) uses hibernate core 5.3.10.Final.

comments powered by Disqus