oracle / oracle-r2dbc

R2DBC Driver for Oracle Database
https://oracle.com
Other
194 stars 40 forks source link

R2DBC 0.1.0 : NoSuchMethodError: Flow$Publisher OracleConnectionBuilder.buildConnectionPublisherOracle() #72

Closed krisparis closed 2 years ago

krisparis commented 2 years ago

I come to you because I am stuck with my Jhipster Spring Boot application, which uses the oracle-r2dbc dependency, when I try to uses my Oracle dependency

My JHipster application also contains the dependency spring-boot-starter-data-r2dbc version 2.6.3 which contains spring-data-r2dbc v1.4.1, r2dbc-spi v0.8.6.RELEASE (which contains oracle-r2dbc version 0.1.0) and r2dbc-pool v0.8.8.RELEASE.

My Oracle Database version is Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production

In my case I have no problem at startup time, liquibase scripts work well, but when calling database from R2dbc api.

Could you help me find a solution on how I could use r2dbc with my Oracle Database ?

Thanks a lot in advance

The following sections give more details about my application, my configuration files, the code that provoke the error and the error stack trace.

Short description of my application

I have multiple maven profiles. One is called "dev" and it uses embeded H2 database. Everything works fine with it. I created a new maven Profile called 'local' in order to connect to my local Oracle Database. No problem at startutp and new tables located in liquibase changelog files are properly created with data in my Oracle database without any errors. Oracle version: Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production

But If i call one of my apis that need to execute some queries then an error is raised with Oracle. Although it works fine when using h2 database. Do you know how I could resolve this problem ?

Below are listed the details of the error and some relevant parts of my configuration files.

Thanks a lot in advance

The JAVA code that provokes the error

In my controller class

@GetMapping("/authorities")
public Mono<List<String>> getAuthorities() {
    return userService.getAuthorities().collectList();
}

In my service class

@Transactional(readOnly = true)
public Flux<String> getAuthorities() {
    return authorityRepository.findAll().map(Authority::getName);
}

The stacktrace of the error

    java.lang.NoSuchMethodError: 'java.util.concurrent.Flow$Publisher oracle.jdbc.OracleConnectionBuilder.buildConnectionPublisherOracle()'
        at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$publishConnection$8(OracleReactiveJdbcAdapter.java:643)
        at oracle.r2dbc.impl.OracleR2dbcExceptions.getOrHandleSQLException(OracleR2dbcExceptions.java:267)
        at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$deferOnce$23(OracleReactiveJdbcAdapter.java:1060)
        at reactor.core.publisher.FluxSource.subscribe(FluxSource.java:67)
        at reactor.core.publisher.Mono.subscribe(Mono.java:4400)
        at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onComplete(FluxConcatArray.java:258)
        at reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:78)
        at reactor.core.publisher.Flux.subscribe(Flux.java:8469)
        at reactor.core.publisher.Flux.subscribeWith(Flux.java:8642)
        at reactor.core.publisher.Flux.subscribe(Flux.java:8439)
        at reactor.core.publisher.Flux.subscribe(Flux.java:8363)
        at reactor.pool.SimpleDequePool.drainLoop(SimpleDequePool.java:423)
        at reactor.pool.SimpleDequePool.pendingOffer(SimpleDequePool.java:558)
        at reactor.pool.SimpleDequePool.doAcquire(SimpleDequePool.java:268)
        at reactor.pool.AbstractPool$Borrower.request(AbstractPool.java:432)

Here are some configurations files that might be important:

The pom.xml file

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-r2dbc</artifactId> <!--  version 2.6.3   -->
</dependency>

...

  <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>             
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
            </dependency>
            <dependency>
                <groupId>io.r2dbc</groupId>
                <artifactId>r2dbc-h2</artifactId>
            </dependency>
        </dependencies>
    </profile>
<profile>
    <id>local</id>           
    <dependencies> 
    <!-- database oracles -->    
    <dependency>
        <groupId>com.oracle.database.r2dbc</groupId>
        <artifactId>oracle-r2dbc</artifactId> <!--  version 0.1.0  -->
    </dependency>           
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <configuration>
                    <filesets>
                        <fileset>
                            <directory>target/classes/static/</directory>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>build-info</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>io.github.git-commit-id</groupId>
                <artifactId>git-commit-id-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <properties>
        <!-- default Spring profiles -->
        <spring.profiles.active>local${profile.api-docs}${profile.tls}</spring.profiles.active>
    </properties>
</profile> 

The file application-local.yml

  liquibase:
    contexts: local, faker
    url: jdbc:oracle:thin:@localhost:1521/xe    
  mail:
    host: localhost
    port: 25
    username:
    password:
  r2dbc:
    url: r2dbc:oracle:thin://localhost:1521/xe
    username: MY_CREDIT    
    password: MY_CREDIT    

Other attempts

I tried to change the r2dbc url to r2dbc:oracle:thin://localhost:1521:xe (: at the end) but it doesn't change anything. I also tried to add other dependencies in the pom like the one below, but no differences:

    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>21.1.0.0</version>
    </dependency>
    <dependency>
        <groupId>com.oracle.database.ha</groupId>
        <artifactId>ons</artifactId>
        <version>21.1.0.0</version>
    </dependency>
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ucp</artifactId>
        <version>21.1.0.0</version>
    </dependency>
Michael-A-McMahon commented 2 years ago

Hi @krisparis,

I see this error: java.lang.NoSuchMethodError: 'java.util.concurrent.Flow$Publisher oracle.jdbc.OracleConnectionBuilder.buildConnectionPublisherOracle()'

This is telling us there is an Oracle JDBC jar is on your class path which does not implement the buildConnectionPublisherOracle method. That method is added in version 21.1.0.0.0, and is only added in the JDK 11 build (ie: it's in ojdbc11.jar, but not in ojdbc8.jar).

You do have a dependency on oracle-r2dbc, and this should pull in the ojdbc11 dependency for 21.x. But I think something else must be declaring a dependency on a pre-21.x version, or on a JDK8/ojdbc8 build, and this dependency is taking precedence on your classpath.

I think that you can resolve this by explicitly declaring a dependency in your pom.xml:

    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc11</artifactId>
      <version>21.5.0.0</version>
    </dependency>

Maven should give precedence to dependencies declared in your pom.xml.

I hope this helps. Let me know how it goes.

krisparis commented 2 years ago

Hello @Michael-A-McMahon ,

Yes I just tried adding ojdbc11 instead of ojdbc8 and this time it worked very well !

Thank you very much for your reactivity and your detailled response. I didn't know where to look but now I understand better how it works.

Thanks a lot and have a nice day !