diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 548ac4f8..f515a064 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -161,4 +161,21 @@ public interface Span { * @see Span#context() */ void finish(long finishMicros); + + /** + * Returns an object that is an instance of the given class to allow access to non-standard methods. + * + *

Using this method is highly preferred to type casts, especially because there might be a hierarchy of wrapper + * objects.

+ * + *

If the class implementing this interface is an instance of the provided class, the this + * reference is returned. Otherwise, if the receiver is a wrapper, return the the result of calling + * unwrap recursively on the wrapped object. If the receiver is not a wrapper and is not an instance of + * the provided class, then null is returned.

+ * + * @param clazz The Class that the result must be an instance of. + * @return an object that is an instance of the provided class, or null if there is no such class in + * the wrapper hierarchy. + */ + T unwrap(java.lang.Class clazz); } diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java index 859513aa..ffd7f6e6 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java @@ -115,6 +115,15 @@ public synchronized void finish(long finishMicros) { this.finished = true; } + @Override + public T unwrap(Class clazz) { + if (clazz.isInstance(this)) { + return clazz.cast(this); + } else { + return null; + } + } + @Override public MockSpan setTag(String key, String value) { return setObjectTag(key, value); diff --git a/opentracing-mock/src/test/java/io/opentracing/mock/MockSpanTest.java b/opentracing-mock/src/test/java/io/opentracing/mock/MockSpanTest.java index b488f657..b258b8ac 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockSpanTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockSpanTest.java @@ -17,6 +17,8 @@ import org.junit.Test; import io.opentracing.Span; +import io.opentracing.Tracer; +import io.opentracing.noop.NoopSpan; /** * @author Pavol Loffay @@ -78,4 +80,18 @@ public void testAddBaggageAfterFinish() { } Assert.assertEquals(1, tracer.finishedSpans().get(0).generatedErrors().size()); } + + @Test + public void testUnwrap() throws Exception { + Tracer tracer = new MockTracer(); + Span span = tracer.buildSpan("foo").startManual(); + Assert.assertSame(span, span.unwrap(MockSpan.class)); + } + + @Test + public void testUnwrapWrongInstance() throws Exception { + Tracer tracer = new MockTracer(); + Span span = tracer.buildSpan("foo").startManual(); + Assert.assertNull(span.unwrap(NoopSpan.class)); + } } diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java index 7d503066..ec09dca7 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java @@ -13,11 +13,11 @@ */ package io.opentracing.noop; +import java.util.Map; + import io.opentracing.Span; import io.opentracing.SpanContext; -import java.util.Map; - public interface NoopSpan extends Span { static final NoopSpan INSTANCE = new NoopSpanImpl(); } @@ -33,6 +33,15 @@ public void finish() {} @Override public void finish(long finishMicros) {} + @Override + public T unwrap(Class clazz) { + if (clazz.isInstance(this)) { + return clazz.cast(this); + } else { + return null; + } + } + @Override public NoopSpan setTag(String key, String value) { return this; }