From 06408794a35131d965a23786a143be044d4c392e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 20 Nov 2025 16:23:48 +0100 Subject: [PATCH 1/6] add nullaway --- .../spring/spring-batch-3.0/javaagent/build.gradle.kts | 1 + .../spring/batch/v3_0/chunk/TracingChunkExecutionListener.java | 2 ++ .../instrumentation/spring/batch/v3_0/item/ItemSingletons.java | 2 ++ .../spring/batch/v3_0/step/TracingStepExecutionListener.java | 1 + .../javaagent/build.gradle.kts | 1 + .../spring/spring-boot-resources/javaagent/build.gradle.kts | 1 + .../spring/resources/SpringBootServiceNameDetector.java | 1 + 7 files changed, 9 insertions(+) diff --git a/instrumentation/spring/spring-batch-3.0/javaagent/build.gradle.kts b/instrumentation/spring/spring-batch-3.0/javaagent/build.gradle.kts index 7841db566744..22b3fbe34fbc 100644 --- a/instrumentation/spring/spring-batch-3.0/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-batch-3.0/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.javaagent-instrumentation") + id("otel.nullaway-conventions") } muzzle { diff --git a/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/chunk/TracingChunkExecutionListener.java b/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/chunk/TracingChunkExecutionListener.java index e456f335c42c..0ef24ed525c6 100644 --- a/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/chunk/TracingChunkExecutionListener.java +++ b/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/chunk/TracingChunkExecutionListener.java @@ -10,6 +10,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.internal.Initializer; import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.ContextAndScope; import javax.annotation.Nullable; @@ -28,6 +29,7 @@ public TracingChunkExecutionListener(Class builderClass) { } @Override + @Initializer public void beforeChunk(ChunkContext chunkContext) { Context parentContext = shouldCreateRootSpanForChunk() ? Context.root() : Context.current(); chunkContextAndBuilder = new ChunkContextAndBuilder(chunkContext, builderClass); diff --git a/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/item/ItemSingletons.java b/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/item/ItemSingletons.java index fb9790800460..68f8dd247058 100644 --- a/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/item/ItemSingletons.java +++ b/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/item/ItemSingletons.java @@ -11,6 +11,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.ContextKey; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import javax.annotation.Nullable; import org.springframework.batch.core.scope.context.ChunkContext; public class ItemSingletons { @@ -47,6 +48,7 @@ public static Context startChunk(Context currentContext, ChunkContext chunkConte return currentContext.with(CHUNK_CONTEXT_KEY, chunkContext); } + @Nullable public static ChunkContext getChunkContext(Context currentContext) { return currentContext.get(CHUNK_CONTEXT_KEY); } diff --git a/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/step/TracingStepExecutionListener.java b/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/step/TracingStepExecutionListener.java index 547ce05e0750..e68b6b65d25e 100644 --- a/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/step/TracingStepExecutionListener.java +++ b/instrumentation/spring/spring-batch-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/batch/v3_0/step/TracingStepExecutionListener.java @@ -37,6 +37,7 @@ public void beforeStep(StepExecution stepExecution) { } @Override + @Nullable public ExitStatus afterStep(StepExecution stepExecution) { ContextAndScope contextAndScope = CONTEXT_AND_SCOPE.get(stepExecution); if (contextAndScope == null) { diff --git a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts index c10e24817dff..1df31255095a 100644 --- a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.javaagent-instrumentation") + id("otel.nullaway-conventions") } muzzle { diff --git a/instrumentation/spring/spring-boot-resources/javaagent/build.gradle.kts b/instrumentation/spring/spring-boot-resources/javaagent/build.gradle.kts index 6417f7c627c7..e7b4c1245b06 100644 --- a/instrumentation/spring/spring-boot-resources/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-boot-resources/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.sdk-extension") + id("otel.nullaway-conventions") } dependencies { diff --git a/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java index e3768574aec3..900934a66b82 100644 --- a/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java +++ b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java @@ -185,6 +185,7 @@ private String findByClasspathBootstrapYaml() { return findByClasspathYamlFile("bootstrap.yaml"); } + @Nullable private String findByClasspathYamlFile(String fileName) { String result = loadFromClasspath(fileName, SpringBootServiceNameDetector::parseNameFromYaml); if (logger.isLoggable(FINER)) { From 0fa5f85e10bb5e7f275b5105692461e7f73213da Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 20 Nov 2025 16:27:16 +0100 Subject: [PATCH 2/6] add nullaway --- .../spring-cloud-aws-3.0/javaagent/build.gradle.kts | 1 + .../spring-cloud-gateway-2.0/javaagent/build.gradle.kts | 1 + .../spring/gateway/v2_0/ServerWebExchangeHelper.java | 8 +++++++- .../spring-cloud-gateway-common/testing/build.gradle.kts | 1 + .../spring/gateway/common/AbstractRouteMappingTest.java | 3 ++- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/build.gradle.kts b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/build.gradle.kts index 60fd14472e50..e345633220a1 100644 --- a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.javaagent-instrumentation") + id("otel.nullaway-conventions") } muzzle { diff --git a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/build.gradle.kts b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/build.gradle.kts index f07a178ba39e..8e0e217bfbc1 100644 --- a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.javaagent-instrumentation") + id("otel.nullaway-conventions") } muzzle { diff --git a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/gateway/v2_0/ServerWebExchangeHelper.java b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/gateway/v2_0/ServerWebExchangeHelper.java index 4bf8abe5fbad..f93f7f4362f2 100644 --- a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/gateway/v2_0/ServerWebExchangeHelper.java +++ b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/gateway/v2_0/ServerWebExchangeHelper.java @@ -13,6 +13,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.LocalRootSpan; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import java.util.regex.Pattern; +import javax.annotation.Nullable; import org.springframework.cloud.gateway.route.Route; import org.springframework.web.server.ServerWebExchange; @@ -68,7 +69,11 @@ public static void extractAttributes(ServerWebExchange exchange, Context context } } - public static String extractServerRoute(ServerWebExchange exchange) { + @Nullable + public static String extractServerRoute(@Nullable ServerWebExchange exchange) { + if (exchange == null) { + return null; + } Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); if (route != null) { return convergeRouteId(route); @@ -83,6 +88,7 @@ public static String extractServerRoute(ServerWebExchange exchange) { * @see */ + @Nullable private static String convergeRouteId(Route route) { String routeId = route.getId(); if (routeId == null || routeId.isEmpty()) { diff --git a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/build.gradle.kts b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/build.gradle.kts index 87e7606308e9..7e8f0a0dd6d5 100644 --- a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/build.gradle.kts +++ b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.java-conventions") + id("otel.nullaway-conventions") } dependencies { diff --git a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/src/main/java/io/opentelemetry/instrumentation/spring/gateway/common/AbstractRouteMappingTest.java b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/src/main/java/io/opentelemetry/instrumentation/spring/gateway/common/AbstractRouteMappingTest.java index b670ef420298..d9b6c94fa8da 100644 --- a/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/src/main/java/io/opentelemetry/instrumentation/spring/gateway/common/AbstractRouteMappingTest.java +++ b/instrumentation/spring/spring-cloud-gateway/spring-cloud-gateway-common/testing/src/main/java/io/opentelemetry/instrumentation/spring/gateway/common/AbstractRouteMappingTest.java @@ -14,6 +14,7 @@ import io.opentelemetry.testing.internal.armeria.client.WebClient; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.beans.factory.annotation.Value; @@ -47,7 +48,7 @@ void beforeEach() { } protected List buildAttributeAssertions( - String routeId, String uri, int order, int filterSize) { + @Nullable String routeId, String uri, int order, int filterSize) { List assertions = new ArrayList<>(); if (!StringUtils.isEmpty(routeId)) { assertions.add(equalTo(AttributeKey.stringKey("spring-cloud-gateway.route.id"), routeId)); From 27e693414de630fd8723c69b9bad08e534e9d3d1 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 20 Nov 2025 16:28:45 +0100 Subject: [PATCH 3/6] add nullaway --- .../spring/spring-core-2.0/javaagent/build.gradle.kts | 1 + .../core/v2_0/SimpleAsyncTaskExecutorInstrumentation.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/instrumentation/spring/spring-core-2.0/javaagent/build.gradle.kts b/instrumentation/spring/spring-core-2.0/javaagent/build.gradle.kts index 791389f3762b..b941235e150b 100644 --- a/instrumentation/spring/spring-core-2.0/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-core-2.0/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.javaagent-instrumentation") + id("otel.nullaway-conventions") } muzzle { diff --git a/instrumentation/spring/spring-core-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/core/v2_0/SimpleAsyncTaskExecutorInstrumentation.java b/instrumentation/spring/spring-core-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/core/v2_0/SimpleAsyncTaskExecutorInstrumentation.java index 96e1bbf0af4a..4ed72968daef 100644 --- a/instrumentation/spring/spring-core-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/core/v2_0/SimpleAsyncTaskExecutorInstrumentation.java +++ b/instrumentation/spring/spring-core-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/core/v2_0/SimpleAsyncTaskExecutorInstrumentation.java @@ -18,6 +18,7 @@ import io.opentelemetry.javaagent.bootstrap.executors.PropagatedContext; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -44,6 +45,7 @@ public void transform(TypeTransformer transformer) { public static class ExecuteAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) + @Nullable public static PropagatedContext enterJobSubmit(@Advice.Argument(0) Runnable task) { Context context = Java8BytecodeBridge.currentContext(); if (ExecutorAdviceHelper.shouldPropagateContext(context, task)) { From 7df30696050102ab79fd95f6527dbb0704b7d0c9 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 20 Nov 2025 16:31:47 +0100 Subject: [PATCH 4/6] add nullaway --- .../spring-data/spring-data-1.8/javaagent/build.gradle.kts | 1 + .../spring/data/v1_8/SpringDataInstrumentationModule.java | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-data/spring-data-1.8/javaagent/build.gradle.kts b/instrumentation/spring/spring-data/spring-data-1.8/javaagent/build.gradle.kts index 6f342906acae..967bf5cde42e 100644 --- a/instrumentation/spring/spring-data/spring-data-1.8/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-data/spring-data-1.8/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.javaagent-instrumentation") + id("otel.nullaway-conventions") } muzzle { diff --git a/instrumentation/spring/spring-data/spring-data-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/data/v1_8/SpringDataInstrumentationModule.java b/instrumentation/spring/spring-data/spring-data-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/data/v1_8/SpringDataInstrumentationModule.java index b751e6977f99..5c06bc9625f2 100644 --- a/instrumentation/spring/spring-data/spring-data-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/data/v1_8/SpringDataInstrumentationModule.java +++ b/instrumentation/spring/spring-data/spring-data-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/data/v1_8/SpringDataInstrumentationModule.java @@ -21,6 +21,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.lang.reflect.Method; import java.util.List; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -89,13 +90,14 @@ public void postProcess(ProxyFactory factory, RepositoryInformation repositoryIn } static final class RepositoryInterceptor implements MethodInterceptor { - private static final Class MONO_CLASS = loadClass("reactor.core.publisher.Mono"); + @Nullable private static final Class MONO_CLASS = loadClass("reactor.core.publisher.Mono"); private final Class repositoryInterface; RepositoryInterceptor(Class repositoryInterface) { this.repositoryInterface = repositoryInterface; } + @Nullable private static Class loadClass(String name) { try { return Class.forName(name); @@ -105,6 +107,7 @@ private static Class loadClass(String name) { } @Override + @Nullable public Object invoke(MethodInvocation methodInvocation) throws Throwable { Context parentContext = currentContext(); Method method = methodInvocation.getMethod(); From e99f00fdf20adb576580307c442cfa595c621ed7 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 20 Nov 2025 16:37:33 +0100 Subject: [PATCH 5/6] add nullaway --- .../javaagent/build.gradle.kts | 1 + .../spring-integration-4.1/library/build.gradle.kts | 1 + .../spring/integration/v4_1/ContextAndScope.java | 2 +- .../integration/v4_1/MessageHeadersGetter.java | 6 +++++- .../integration/v4_1/MessageHeadersSetter.java | 6 +++++- .../integration/v4_1/TracingChannelInterceptor.java | 13 ++++++++++++- 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/instrumentation/spring/spring-integration-4.1/javaagent/build.gradle.kts b/instrumentation/spring/spring-integration-4.1/javaagent/build.gradle.kts index ad76d268a5a9..c39d2c92acce 100644 --- a/instrumentation/spring/spring-integration-4.1/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-integration-4.1/javaagent/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.javaagent-instrumentation") + id("otel.nullaway-conventions") } // context "leak" here is intentional: spring-integration instrumentation will always override diff --git a/instrumentation/spring/spring-integration-4.1/library/build.gradle.kts b/instrumentation/spring/spring-integration-4.1/library/build.gradle.kts index f32dcf2c61d5..8e49145ec8bb 100644 --- a/instrumentation/spring/spring-integration-4.1/library/build.gradle.kts +++ b/instrumentation/spring/spring-integration-4.1/library/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.library-instrumentation") + id("otel.nullaway-conventions") } dependencies { diff --git a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/ContextAndScope.java b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/ContextAndScope.java index 5d2c0440757a..3bbf4ac5f8e4 100644 --- a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/ContextAndScope.java +++ b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/ContextAndScope.java @@ -22,7 +22,7 @@ void close() { getScope().close(); } - static ContextAndScope create(Context context, Scope scope) { + static ContextAndScope create(@Nullable Context context, Scope scope) { return new AutoValue_ContextAndScope(context, scope); } } diff --git a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersGetter.java b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersGetter.java index 5ccd62b0a918..5d36f6f6d9c1 100644 --- a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersGetter.java +++ b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersGetter.java @@ -31,7 +31,11 @@ public Iterable keys(MessageWithChannel carrier) { } @Override - public String get(MessageWithChannel carrier, String key) { + @Nullable + public String get(@Nullable MessageWithChannel carrier, String key) { + if (carrier == null) { + return null; + } MessageHeaders headers = carrier.getMessage().getHeaders(); String nativeHeaderValue = getNativeHeader(headers, key); if (nativeHeaderValue != null) { diff --git a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersSetter.java b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersSetter.java index 58c60ca6739d..9d4eefb6298b 100644 --- a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersSetter.java +++ b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/MessageHeadersSetter.java @@ -10,6 +10,7 @@ import io.opentelemetry.context.propagation.TextMapSetter; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.messaging.support.NativeMessageHeaderAccessor; @@ -21,7 +22,10 @@ enum MessageHeadersSetter implements TextMapSetter { INSTANCE; @Override - public void set(MessageHeaderAccessor carrier, String key, String value) { + public void set(@Nullable MessageHeaderAccessor carrier, String key, String value) { + if (carrier == null) { + return; + } carrier.setHeader(key, value); setNativeHeader(carrier, key, value); } diff --git a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/TracingChannelInterceptor.java b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/TracingChannelInterceptor.java index 76828cce49f5..6215a7db5722 100644 --- a/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/TracingChannelInterceptor.java +++ b/instrumentation/spring/spring-integration-4.1/library/src/main/java/io/opentelemetry/instrumentation/spring/integration/v4_1/TracingChannelInterceptor.java @@ -16,6 +16,7 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; import org.springframework.messaging.Message; @@ -202,11 +203,15 @@ private static Message createMessageWithHeaders( .build(); } + @Nullable private static final Class directWithAttributesChannelClass = getDirectWithAttributesChannelClass(); + + @Nullable private static final MethodHandle channelGetAttributeMh = getChannelAttributeMh(directWithAttributesChannelClass); + @Nullable private static Class getDirectWithAttributesChannelClass() { try { return Class.forName( @@ -216,7 +221,9 @@ private static Class getDirectWithAttributesChannelClass() { } } - private static MethodHandle getChannelAttributeMh(Class directWithAttributesChannelClass) { + @Nullable + private static MethodHandle getChannelAttributeMh( + @Nullable Class directWithAttributesChannelClass) { if (directWithAttributesChannelClass == null) { return null; } @@ -244,6 +251,10 @@ private boolean createProducerSpan(MessageChannel messageChannel) { return false; } + if (channelGetAttributeMh == null) { + return false; + } + try { return "output".equals(channelGetAttributeMh.invoke(messageChannel, "type")); } catch (Throwable throwable) { From 055bb4f2ca8eae1c461b539179b7f3d42a54c526 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 20 Nov 2025 17:24:54 +0100 Subject: [PATCH 6/6] add nullaway --- .../aws/AcknowledgementExecutionContextInstrumentation.java | 2 ++ .../aws/MessagingMessageListenerAdapterInstrumentation.java | 2 ++ .../javaagent/instrumentation/spring/aws/SpringAwsUtil.java | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AcknowledgementExecutionContextInstrumentation.java b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AcknowledgementExecutionContextInstrumentation.java index 51ab27ccbbe4..2e9ba1a431d8 100644 --- a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AcknowledgementExecutionContextInstrumentation.java +++ b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AcknowledgementExecutionContextInstrumentation.java @@ -11,6 +11,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.Collection; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -32,6 +33,7 @@ public void transform(TypeTransformer transformer) { @SuppressWarnings("unused") public static class ExecuteAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) + @Nullable public static Scope methodEnter(@Advice.Argument(0) Collection> messages) { return SpringAwsUtil.handleBatch(messages); } diff --git a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/MessagingMessageListenerAdapterInstrumentation.java b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/MessagingMessageListenerAdapterInstrumentation.java index 89c7be3ebe17..36795361f738 100644 --- a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/MessagingMessageListenerAdapterInstrumentation.java +++ b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/MessagingMessageListenerAdapterInstrumentation.java @@ -10,6 +10,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -33,6 +34,7 @@ public void transform(TypeTransformer transformer) { @SuppressWarnings("unused") public static class OnMessageAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) + @Nullable public static SpringAwsUtil.MessageScope methodEnter(@Advice.Argument(0) Message message) { return SpringAwsUtil.handleMessage(message); } diff --git a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/SpringAwsUtil.java b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/SpringAwsUtil.java index 66731302e669..eb059e6adf18 100644 --- a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/SpringAwsUtil.java +++ b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/aws/SpringAwsUtil.java @@ -17,6 +17,7 @@ import io.opentelemetry.instrumentation.awssdk.v2_2.internal.TracingExecutionInterceptor; import io.opentelemetry.instrumentation.awssdk.v2_2.internal.TracingList; import java.util.Collection; +import javax.annotation.Nullable; import org.springframework.messaging.Message; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; @@ -61,6 +62,7 @@ public static void copyTracingState(Message original, Message transformed) tracingContextField.set(transformed, tracingContextField.get(original)); } + @Nullable public static MessageScope handleMessage(Message message) { TracingContext tracingContext = tracingContextField.get(message); if (tracingContext == null) { @@ -71,6 +73,7 @@ public static MessageScope handleMessage(Message message) { } // restore context from the first message of the batch + @Nullable public static Scope handleBatch(Collection> messages) { if (messages == null || messages.isEmpty()) { return null; @@ -131,6 +134,7 @@ private static class TracingContext { this.sqsMessage = sqsMessage; } + @Nullable MessageScope trace() { SqsMessage wrappedMessage = SqsMessageImpl.wrap(sqsMessage); Context parentContext = receiveContext;