micronaut-projects / micronaut-sql

Projects to support SQL Database access in Micronaut
Apache License 2.0
74 stars 42 forks source link

Postgres doesn't work with hibernate-reactive #742

Closed timyates closed 8 months ago

timyates commented 1 year ago

Expected Behavior

Hibernate Reactive should work with Postgres databases.

Actual Behaviour

When you attempt to do something that touches the database (such as run the app or a test), it throws the following exception:

13:43:42.201 [vert.x-eventloop-thread-2] ERROR i.m.http.server.RouteExecutor - Unexpected error occurred: com/ongres/scram/common/stringprep/StringPreparation
java.lang.NoClassDefFoundError: com/ongres/scram/common/stringprep/StringPreparation
    at io.vertx.pgclient.impl.codec.InitCommandCodec.handleAuthenticationSasl(InitCommandCodec.java:60)
    at io.vertx.pgclient.impl.codec.PgDecoder.decodeAuthentication(PgDecoder.java:366)
    at io.vertx.pgclient.impl.codec.PgDecoder.decodeMessage(PgDecoder.java:140)
    at io.vertx.pgclient.impl.codec.PgDecoder.channelRead(PgDecoder.java:112)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.ClassNotFoundException: com.ongres.scram.common.stringprep.StringPreparation
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)

It seems to be missing a dependency (as described here https://vertx.io/docs/vertx-pg-client/java/#_sasl_scram_sha_256_authentication_mechanism), and indeed adding

    implementation("com.ongres.scram:client:2.1")

To the build makes it work... Should this be a default dependency? Or is there some configuration to turn off this requirement?

Steps To Reproduce

  1. Download the MySql guide from https://guides.micronaut.io/latest/micronaut-hibernate-reactive-gradle-java.zip
  2. Apply this diff to switch to postgres:

    diff --git a/build.gradle b/build.gradle
    index ea7646b..0524901 100644
    --- a/build.gradle
    +++ b/build.gradle
    @@ -18,15 +18,15 @@ dependencies {
         implementation("io.micronaut.reactor:micronaut-reactor")
         implementation("io.micronaut.reactor:micronaut-reactor-http-client")
         implementation("io.micronaut.sql:micronaut-hibernate-reactive")
    -    implementation("io.vertx:vertx-mysql-client")
    +    implementation("io.vertx:vertx-pg-client")
    +    implementation("com.ongres.scram:client:2.1")
         implementation("jakarta.annotation:jakarta.annotation-api")
         implementation("jakarta.persistence:jakarta.persistence-api:3.1.0")
         runtimeOnly("ch.qos.logback:logback-classic")
         testImplementation("org.testcontainers:junit-jupiter")
    -    testImplementation("org.testcontainers:mysql")
    +    testImplementation("org.testcontainers:postgresql")
         testImplementation("org.testcontainers:testcontainers")
         implementation("io.micronaut:micronaut-validation")
    -
     }
    
    diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
    index 32034a2..8efb770 100644
    --- a/src/main/resources/application-dev.yml
    +++ b/src/main/resources/application-dev.yml
    @@ -3,6 +3,6 @@ jpa:
         properties:
           hibernate:
             connection:
    -          url: jdbc:mysql://localhost:3306/mysql # Use JDBC style url
    +          url: jdbc:postgresql://localhost:5432/postgres
               username: root
               password: pass
    diff --git a/src/test/java/example/micronaut/BaseMysqlTest.java b/src/test/java/example/micronaut/BaseMysqlTest.java
    index f7eb254..96cb96f 100644
    --- a/src/test/java/example/micronaut/BaseMysqlTest.java
    +++ b/src/test/java/example/micronaut/BaseMysqlTest.java
    @@ -31,10 +31,10 @@ public class BaseMysqlTest implements TestPropertyProvider { // <3>
    
         void startMySQL() {
             if (mysqlContainer == null) {
    -            mysqlContainer = new GenericContainer<>(DockerImageName.parse("mysql:oracle"))
    -                    .withExposedPorts(3306)
    -                    .withEnv("MYSQL_ROOT_PASSWORD", "pass")
    -                    .waitingFor(Wait.forLogMessage(".*/usr/sbin/mysqld: ready for connections.*\\n", 2));
    +            mysqlContainer = new GenericContainer<>(DockerImageName.parse("postgres"))
    +                    .withExposedPorts(5432)
    +                    .withEnv("POSTGRES_PASSWORD", "pass")
    +                    .waitingFor(Wait.forLogMessage(".*database system is ready to accept connections.*\\n", 2));
             }
             if (!mysqlContainer.isRunning()) {
                 mysqlContainer.start();
    @@ -45,7 +45,7 @@ public class BaseMysqlTest implements TestPropertyProvider { // <3>
             if (mysqlContainer == null || !mysqlContainer.isRunning()) {
                 startMySQL();
             }
    -        return "jdbc:mysql://localhost:" + mysqlContainer.getMappedPort(3306) + "/mysql";
    +        return "jdbc:postgresql://localhost:" + mysqlContainer.getMappedPort(5432) + "/postgres";
         }
    
         @Override
    diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml
    index 159c9ed..25106bc 100644
    --- a/src/test/resources/application-test.yml
    +++ b/src/test/resources/application-test.yml
    @@ -3,5 +3,5 @@ jpa:
         properties:
           hibernate:
             connection:
    -          username: root
    +          username: postgres
               password: pass
  3. run ./gradlew test to see the failure
  4. Add implementation("com.ongres.scram:client:2.1") to the build
  5. run ./gradlew test to see it passing

Environment Information

No response

Example Application

No response

Version

3.7.2

timyates commented 1 year ago

I believe this is also an issue with micronaut-data hibernate-reactive

radovanradic commented 8 months ago

It's been a while when this issue was created. Added runtime dependency for ongres client here https://github.com/micronaut-projects/micronaut-sql/pull/1243/files#diff-ffdbca91a95ed7955cdb987624acd5ddc14ba73e4d90210ace6509d592419b7e and it should be fixed in next micronaut-sql release.