javaspring-bootmavenokhttpopen-telemetry

Spring Boot 4.0.0-M1 java.lang.NoClassDefFoundError: Could not initialize class io.opentelemetry.exporter.sender.okhttp.internal.OkHttpGrpcSender


I would like to build a native image with the newly released (as of this writing) Spring Boot 4.0.0-M1 and GraalVM AOT

With this code:

@Configuration
public class TracingConfiguration {

    @Bean
    public SpanExporter otlpGrpcSpanExporter() {
        return OtlpGrpcSpanExporter.builder().setEndpoint("https://otlp-gateway-prod-us-central-0.grafana.net/otlp/v1/traces").addHeader("Authorization", "Basic ODY2MTg0OaWRYTWlmWDA9").build(); //this is fake
    }

}

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-kafka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-opentelemetry</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-webclient</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-core-micrometer</artifactId>
    </dependency>
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-tracing-bridge-otel</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-otlp</artifactId>
    </dependency>

    <dependency>
        <groupId>io.projectreactor.kafka</groupId>
        <artifactId>reactor-kafka</artifactId>
        <version>1.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-function-context</artifactId>
        <version>4.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.github.loki4j</groupId>
        <artifactId>loki-logback-appender</artifactId>
        <version>2.0.0</version>
    </dependency>
<!--        <dependency>-->
<!--            <groupId>io.opentelemetry</groupId>-->
<!--            <artifactId>opentelemetry-exporter-sender-okhttp</artifactId>-->
<!--            <version>1.52.0</version>-->
<!--        </dependency>-->

</dependencies>

mvn -U -Pnative spring-boot:build-image -DskipTests

I get this error message:

Caused by: java.lang.NoClassDefFoundError: Could not initialize class io.opentelemetry.exporter.sender.okhttp.internal.OkHttpGrpcSender
        at io.opentelemetry.exporter.sender.okhttp.internal.OkHttpGrpcSenderProvider.createSender(OkHttpGrpcSenderProvider.java:23)
        at io.opentelemetry.exporter.internal.grpc.GrpcExporterBuilder.build(GrpcExporterBuilder.java:236)
        at io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder.build(OtlpGrpcSpanExporterBuilder.java:310)
        at org.example.TracingConfiguration.otlpGrpcSpanExporter(TracingConfiguration.java:25)

With version 3.5.3, this would compile fine and run fine. With version 4.0.0-M1, it will always yield java.lang.NoClassDefFoundError: Could not initialize class io.opentelemetry.exporter.sender.okhttp.internal.OkHttpGrpcSender

I understand Spring Boot has been modularized for 4.0, which is a great thing.

Which module contains this?

How to fix this issue so the native image can be built?


Solution

  • You hit an open bug opentelemetry-exporter-sender-okhttp:1.52.0 consumed in Maven based applications fails due to missing OkHttp classes #7491

    The version of com.squareup.okhttp3:okhttp used by OpenTelemetry 1.52.0 changed from 4.12.0 to 5.1.0. As documented in the OkHttp release notes since 5.0.0 OkHttp build artifacts now use Gradle module metadata. Also, OkHttp now publishes separate JVM and Android build artifacts. Applications built using Gradle are not affected, as Gradle automatically uses the appropriate build artifact. However, applications built using Maven are affected as they are not Gradle module metadata aware. Overriding the transitive dependency on com.squareup.okhttp3:okhttp to instead be com.squareup.okhttp3:okhttp-jvm fixes the example repro detailed above.

    As a workaround, add com.squareup.okhttp3:okhttp-jvm dependency

    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp-jvm</artifactId>
      <version>5.1.0</version>
    </dependency>