diff --git a/spring-core/src/main/java/org/springframework/core/PropagationContextElement.java b/spring-core/src/main/java/org/springframework/core/PropagationContextElement.java
new file mode 100644
index 00000000000..9a2addad645
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/core/PropagationContextElement.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2002-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.core;
+
+import io.micrometer.context.ContextRegistry;
+import io.micrometer.context.ContextSnapshot;
+import io.micrometer.context.ContextSnapshotFactory;
+import kotlin.coroutines.AbstractCoroutineContextElement;
+import kotlin.coroutines.CoroutineContext;
+import kotlinx.coroutines.ThreadContextElement;
+import kotlinx.coroutines.reactor.ReactorContext;
+import org.jspecify.annotations.Nullable;
+import reactor.util.context.ContextView;
+
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link ThreadContextElement} that ensures that contexts registered with the
+ * Micrometer Context Propagation library are captured and restored when
+ * a coroutine is resumed on a thread. This is typically being used for
+ * Micrometer Tracing support in Kotlin suspended functions.
+ *
+ *
It requires the {@code io.micrometer:context-propagation} library. If the
+ * {@code org.jetbrains.kotlinx:kotlinx-coroutines-reactor} dependency is also
+ * on the classpath, this element also supports Reactor {@code Context}.
+ *
+ *
{@code PropagationContextElement} can be used like this:
+ *
+ *
+ * fun main() {
+ * runBlocking(Dispatchers.IO + PropagationContextElement()) {
+ * suspendingFunction()
+ * }
+ * }
+ *
+ * suspend fun suspendingFunction() {
+ * delay(1)
+ * logger.info("Log statement with traceId")
+ * }
+ *
+ *
+ * @author Brian Clozel
+ * @author Sebastien Deleuze
+ * @since 7.0
+ */
+public final class PropagationContextElement extends AbstractCoroutineContextElement implements ThreadContextElement {
+
+ /**
+ * {@code PropagationContextElement} key.
+ */
+ public static final Key Key = new Key();
+
+ private static final ContextSnapshotFactory contextSnapshotFactory = ContextSnapshotFactory.builder()
+ .contextRegistry(ContextRegistry.getInstance()).build();
+
+ private static final boolean coroutinesReactorPresent = ClassUtils.isPresent("kotlinx.coroutines.reactor.ReactorContext",
+ PropagationContextElement.class.getClassLoader());
+
+ private final ContextSnapshot threadLocalContextSnapshot;
+
+
+ public PropagationContextElement() {
+ super(Key);
+ this.threadLocalContextSnapshot = contextSnapshotFactory.captureAll();
+ }
+
+ public void restoreThreadContext(CoroutineContext context, ContextSnapshot.Scope oldState) {
+ oldState.close();
+ }
+
+ public ContextSnapshot.Scope updateThreadContext(CoroutineContext context) {
+ ContextSnapshot contextSnapshot;
+ if (coroutinesReactorPresent) {
+ contextSnapshot = ReactorDelegate.captureFrom(context);
+ if (contextSnapshot == null) {
+ contextSnapshot = this.threadLocalContextSnapshot;
+ }
+ }
+ else {
+ contextSnapshot = this.threadLocalContextSnapshot;
+ }
+ return contextSnapshot.setThreadLocals();
+ }
+
+ public static final class Key implements CoroutineContext.Key {
+ }
+
+ private static final class ReactorDelegate {
+
+ @Nullable
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public static ContextSnapshot captureFrom(CoroutineContext context) {
+ ReactorContext reactorContext = (ReactorContext)context.get((CoroutineContext.Key)ReactorContext.Key);
+ ContextView contextView = reactorContext != null ? reactorContext.getContext() : null;
+ if (contextView != null) {
+ return contextSnapshotFactory.captureFrom(contextView);
+ }
+ else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/spring-core/src/main/kotlin/org/springframework/core/PropagationContextElement.kt b/spring-core/src/main/kotlin/org/springframework/core/PropagationContextElement.kt
deleted file mode 100644
index ad7ae35948a..00000000000
--- a/spring-core/src/main/kotlin/org/springframework/core/PropagationContextElement.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2002-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.core
-
-import io.micrometer.context.ContextRegistry
-import io.micrometer.context.ContextSnapshot
-import io.micrometer.context.ContextSnapshotFactory
-import kotlinx.coroutines.ThreadContextElement
-import kotlinx.coroutines.reactor.ReactorContext
-import org.springframework.util.ClassUtils
-import reactor.util.context.ContextView
-import kotlin.coroutines.AbstractCoroutineContextElement
-import kotlin.coroutines.CoroutineContext
-
-
-/**
- * [ThreadContextElement] that ensures that contexts registered with the
- * Micrometer Context Propagation library are captured and restored when
- * a coroutine is resumed on a thread. This is typically being used for
- * Micrometer Tracing support in Kotlin suspended functions.
- *
- * It requires the `io.micrometer:context-propagation` library. If the
- * `org.jetbrains.kotlinx:kotlinx-coroutines-reactor` dependency is also
- * on the classpath, this element also supports Reactor `Context`.
- *
- * `PropagationContextElement` can be used like this:
- *
- * ```kotlin
- * fun main() {
- * runBlocking(Dispatchers.IO + PropagationContextElement()) {
- * suspendingFunction()
- * }
- * }
- *
- * suspend fun suspendingFunction() {
- * delay(1)
- * logger.info("Log statement with traceId")
- * }
- * ```
- *
- * @author Brian Clozel
- * @author Sebastien Deleuze
- * @since 7.0
- */
-class PropagationContextElement : ThreadContextElement,
- AbstractCoroutineContextElement(Key) {
-
- companion object Key : CoroutineContext.Key {
-
- private val contextSnapshotFactory =
- ContextSnapshotFactory.builder().contextRegistry(ContextRegistry.getInstance()).build()
-
- private val coroutinesReactorPresent =
- ClassUtils.isPresent("kotlinx.coroutines.reactor.ReactorContext",
- PropagationContextElement::class.java.classLoader);
- }
-
- // Context captured from the the ThreadLocal where the PropagationContextElement is instantiated
- private val threadLocalContextSnapshot: ContextSnapshot = contextSnapshotFactory.captureAll()
-
- override fun restoreThreadContext(context: CoroutineContext, oldState: ContextSnapshot.Scope) {
- oldState.close()
- }
-
- override fun updateThreadContext(context: CoroutineContext): ContextSnapshot.Scope {
- val contextSnapshot = if (coroutinesReactorPresent) {
- ReactorDelegate().captureFrom(context) ?: threadLocalContextSnapshot
- } else {
- threadLocalContextSnapshot
- }
- return contextSnapshot.setThreadLocals()
- }
-
- private class ReactorDelegate {
-
- fun captureFrom(context: CoroutineContext): ContextSnapshot? {
- val contextView: ContextView? = context[ReactorContext]?.context
- if (contextView != null) {
- return contextSnapshotFactory.captureFrom(contextView)
- }
- return null;
- }
- }
-}