From 48a137135fbbf9385138e847fb5a7e8206eb2dad Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 21 Jul 2018 09:21:27 +0800 Subject: [PATCH] Removes bytecode so we can add more This removes the auto-value dependency and related for inlining the few cases where it was used. It also trims the class hierarchy of sampling flags. Finally, it moves out the in-flight localEndpoint as it is constant. Besides fixing a few bugs, these changes reduced the size of the jar by 12KiB and scraps 2 dependencies. ```bash du -k /Users/acole/.m2/repository/io/zipkin/brave/brave/5.1.2/brave-5.1.2.jar /Users/acole/.m2/repository/io/zipkin/brave/brave/5.1.3-SNAPSHOT/brave-5.1.3-SNAPSHOT.jar 116 /Users/acole/.m2/repository/io/zipkin/brave/brave/5.1.2/brave-5.1.2.jar 128 /Users/acole/.m2/repository/io/zipkin/brave/brave/5.1.3-SNAPSHOT/brave-5.1.3-SNAPSHOT.jar ``` --- brave/pom.xml | 12 -- brave/src/main/java/brave/NoopScopedSpan.java | 16 ++ brave/src/main/java/brave/NoopSpan.java | 28 ++- brave/src/main/java/brave/RealScopedSpan.java | 16 +- brave/src/main/java/brave/RealSpan.java | 67 +++++--- .../main/java/brave/RealSpanCustomizer.java | 21 ++- brave/src/main/java/brave/Tracer.java | 28 ++- .../brave/internal/recorder/MutableSpan.java | 49 ++---- .../internal/recorder/MutableSpanMap.java | 4 +- .../brave/internal/recorder/Recorder.java | 12 +- .../java/brave/propagation/SamplingFlags.java | 100 ++++++----- .../brave/propagation/ThreadLocalSpan.java | 60 ++++--- .../java/brave/propagation/TraceContext.java | 13 +- .../brave/propagation/TraceIdContext.java | 13 +- .../internal/recorder/MutableSpanMapTest.java | 8 +- .../internal/recorder/MutableSpanTest.java | 58 ++++--- .../brave/internal/recorder/RecorderTest.java | 2 +- .../brave/propagation/SamplingFlagsTest.java | 8 + .../brave/sampler/DeclarativeSamplerTest.java | 19 ++- instrumentation/grpc/pom.xml | 6 - instrumentation/http/pom.xml | 11 -- .../main/java/brave/http/HttpRuleSampler.java | 35 ++-- .../src/main/java/brave/http/HttpTracing.java | 160 +++++++++++++----- instrumentation/jaxrs2/pom.xml | 1 + pom.xml | 11 -- 25 files changed, 442 insertions(+), 316 deletions(-) diff --git a/brave/pom.xml b/brave/pom.xml index 2485d0105f..08288867f9 100644 --- a/brave/pom.xml +++ b/brave/pom.xml @@ -34,18 +34,6 @@ provided - - - com.google.auto.value - auto-value - provided - - - - javax.annotation - javax.annotation-api - provided - org.powermock diff --git a/brave/src/main/java/brave/NoopScopedSpan.java b/brave/src/main/java/brave/NoopScopedSpan.java index 285fb652bb..908fc41109 100644 --- a/brave/src/main/java/brave/NoopScopedSpan.java +++ b/brave/src/main/java/brave/NoopScopedSpan.java @@ -40,4 +40,20 @@ final class NoopScopedSpan extends ScopedSpan { @Override public String toString() { return "NoopScopedSpan(" + context + ")"; } + + @Override public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof NoopScopedSpan)) return false; + NoopScopedSpan that = (NoopScopedSpan) o; + return context.equals(that.context) && scope.equals(that.scope); + } + + @Override public int hashCode() { + int h = 1; + h *= 1000003; + h ^= context.hashCode(); + h *= 1000003; + h ^= scope.hashCode(); + return h; + } } diff --git a/brave/src/main/java/brave/NoopSpan.java b/brave/src/main/java/brave/NoopSpan.java index 4a17203f07..7b5cafbd81 100644 --- a/brave/src/main/java/brave/NoopSpan.java +++ b/brave/src/main/java/brave/NoopSpan.java @@ -1,14 +1,14 @@ package brave; import brave.propagation.TraceContext; -import com.google.auto.value.AutoValue; import zipkin2.Endpoint; -@AutoValue -abstract class NoopSpan extends Span { +final class NoopSpan extends Span { - static NoopSpan create(TraceContext context) { - return new AutoValue_NoopSpan(context); + final TraceContext context; + + NoopSpan(TraceContext context) { + this.context = context; } @Override public SpanCustomizer customizer() { @@ -19,6 +19,10 @@ static NoopSpan create(TraceContext context) { return true; } + @Override public TraceContext context() { + return context; + } + @Override public Span start() { return this; } @@ -66,4 +70,18 @@ static NoopSpan create(TraceContext context) { @Override public void flush() { } + + @Override public String toString() { + return "NoopSpan(" + context + ")"; + } + + @Override public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof NoopSpan)) return false; + return context.equals(((NoopSpan) o).context); + } + + @Override public int hashCode() { + return context.hashCode(); + } } diff --git a/brave/src/main/java/brave/RealScopedSpan.java b/brave/src/main/java/brave/RealScopedSpan.java index 7347b5f0e7..be5c1075ce 100644 --- a/brave/src/main/java/brave/RealScopedSpan.java +++ b/brave/src/main/java/brave/RealScopedSpan.java @@ -47,7 +47,19 @@ final class RealScopedSpan extends ScopedSpan { recorder.finish(context); } - @Override public String toString() { - return "RealScopedSpan(" + context + ")"; + @Override public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof RealScopedSpan)) return false; + RealScopedSpan that = (RealScopedSpan) o; + return context.equals(that.context) && scope.equals(that.scope); + } + + @Override public int hashCode() { + int h = 1; + h *= 1000003; + h ^= context.hashCode(); + h *= 1000003; + h ^= scope.hashCode(); + return h; } } diff --git a/brave/src/main/java/brave/RealSpan.java b/brave/src/main/java/brave/RealSpan.java index ec1190bb46..5f4b87cf2c 100644 --- a/brave/src/main/java/brave/RealSpan.java +++ b/brave/src/main/java/brave/RealSpan.java @@ -2,88 +2,107 @@ import brave.internal.recorder.Recorder; import brave.propagation.TraceContext; -import com.google.auto.value.AutoValue; import zipkin2.Endpoint; /** This wraps the public api and guards access to a mutable span. */ -@AutoValue -abstract class RealSpan extends Span { +final class RealSpan extends Span { - abstract Recorder recorder(); - abstract ErrorParser errorParser(); + final TraceContext context; + final Recorder recorder; + final ErrorParser errorParser; + final RealSpanCustomizer customizer; - static RealSpan create(TraceContext context, Recorder recorder, ErrorParser errorParser) { - return new AutoValue_RealSpan(context, RealSpanCustomizer.create(context, recorder), recorder, - errorParser); + RealSpan(TraceContext context, Recorder recorder, ErrorParser errorParser) { + this.context = context; + this.recorder = recorder; + this.customizer = new RealSpanCustomizer(context, recorder); + this.errorParser = errorParser; } @Override public boolean isNoop() { return false; } + @Override public TraceContext context() { + return context; + } + + @Override public SpanCustomizer customizer() { + return new RealSpanCustomizer(context, recorder); + } + @Override public Span start() { - recorder().start(context()); + recorder.start(context()); return this; } @Override public Span start(long timestamp) { - recorder().start(context(), timestamp); + recorder.start(context(), timestamp); return this; } @Override public Span name(String name) { - recorder().name(context(), name); + recorder.name(context(), name); return this; } @Override public Span kind(Kind kind) { - recorder().kind(context(), kind); + recorder.kind(context(), kind); return this; } @Override public Span annotate(String value) { - recorder().annotate(context(), value); + recorder.annotate(context(), value); return this; } @Override public Span annotate(long timestamp, String value) { - recorder().annotate(context(), timestamp, value); + recorder.annotate(context(), timestamp, value); return this; } @Override public Span tag(String key, String value) { - recorder().tag(context(), key, value); + recorder.tag(context(), key, value); return this; } @Override public Span error(Throwable throwable) { - errorParser().error(throwable, customizer()); + errorParser.error(throwable, customizer()); return this; } @Override public Span remoteEndpoint(Endpoint remoteEndpoint) { - recorder().remoteEndpoint(context(), remoteEndpoint); + recorder.remoteEndpoint(context(), remoteEndpoint); return this; } @Override public void finish() { - recorder().finish(context()); + recorder.finish(context()); } @Override public void finish(long timestamp) { - recorder().finish(context(), timestamp); + recorder.finish(context(), timestamp); } @Override public void abandon() { - recorder().abandon(context()); + recorder.abandon(context()); } @Override public void flush() { - recorder().flush(context()); + recorder.flush(context()); + } + + @Override public String toString() { + return "RealSpan(" + context + ")"; + } + + @Override public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof RealSpan)) return false; + return context.equals(((RealSpan) o).context); } - @Override - public String toString() { - return "RealSpan(" + context() + ")"; + @Override public int hashCode() { + return context.hashCode(); } } diff --git a/brave/src/main/java/brave/RealSpanCustomizer.java b/brave/src/main/java/brave/RealSpanCustomizer.java index 6955e76a46..ac20b6713d 100644 --- a/brave/src/main/java/brave/RealSpanCustomizer.java +++ b/brave/src/main/java/brave/RealSpanCustomizer.java @@ -2,36 +2,35 @@ import brave.internal.recorder.Recorder; import brave.propagation.TraceContext; -import com.google.auto.value.AutoValue; /** This wraps the public api and guards access to a mutable span. */ -@AutoValue -abstract class RealSpanCustomizer implements SpanCustomizer { +final class RealSpanCustomizer implements SpanCustomizer { - abstract TraceContext context(); - abstract Recorder recorder(); + final TraceContext context; + final Recorder recorder; - static RealSpanCustomizer create(TraceContext context, Recorder recorder) { - return new AutoValue_RealSpanCustomizer(context, recorder); + RealSpanCustomizer(TraceContext context, Recorder recorder) { + this.context = context; + this.recorder = recorder; } @Override public SpanCustomizer name(String name) { - recorder().name(context(), name); + recorder.name(context, name); return this; } @Override public SpanCustomizer annotate(String value) { - recorder().annotate(context(), value); + recorder.annotate(context, value); return this; } @Override public SpanCustomizer tag(String key, String value) { - recorder().tag(context(), key, value); + recorder.tag(context, key, value); return this; } @Override public String toString() { - return "RealSpanCustomizer(" + context() + ")"; + return "RealSpanCustomizer(" + context + ")"; } } diff --git a/brave/src/main/java/brave/Tracer.java b/brave/src/main/java/brave/Tracer.java index b63922b7b6..cd2cc6eadd 100644 --- a/brave/src/main/java/brave/Tracer.java +++ b/brave/src/main/java/brave/Tracer.java @@ -246,10 +246,8 @@ public Span nextSpan(TraceContextOrSamplingFlags extracted) { public Span toSpan(TraceContext context) { if (context == null) throw new NullPointerException("context == null"); TraceContext decorated = propagationFactory.decorate(context); - if (!noop.get() && Boolean.TRUE.equals(decorated.sampled())) { - return RealSpan.create(decorated, recorder, errorParser); - } - return NoopSpan.create(decorated); + if (isNoop(context)) return new NoopSpan(decorated); + return new RealSpan(decorated, recorder, errorParser); } /** @@ -308,9 +306,9 @@ public SpanInScope withSpanInScope(@Nullable Span span) { * as a method-local variable vs repeated calls. */ public SpanCustomizer currentSpanCustomizer() { - TraceContext currentContext = currentTraceContext.get(); - return currentContext != null && Boolean.TRUE.equals(currentContext.sampled()) - ? RealSpanCustomizer.create(currentContext, recorder) : NoopSpanCustomizer.INSTANCE; + TraceContext context = currentTraceContext.get(); + if (context == null || isNoop(context)) return NoopSpanCustomizer.INSTANCE; + return new RealSpanCustomizer(context, recorder); } /** @@ -367,14 +365,10 @@ public ScopedSpan startScopedSpanWithParent(String name, @Nullable TraceContext if (name == null) throw new NullPointerException("name == null"); TraceContext context = propagationFactory.decorate(newContextBuilder(parent, sampler).build()); CurrentTraceContext.Scope scope = currentTraceContext.newScope(context); - ScopedSpan result; - if (!noop.get() && Boolean.TRUE.equals(context.sampled())) { - result = new RealScopedSpan(context, scope, recorder, errorParser); - recorder.name(context, name); - recorder.start(context); - } else { - result = new NoopScopedSpan(context, scope); - } + if (isNoop(context)) return new NoopScopedSpan(context, scope); + ScopedSpan result = new RealScopedSpan(context, scope, recorder, errorParser); + recorder.name(context, name); + recorder.start(context); return result; } @@ -425,6 +419,10 @@ TraceContext.Builder newContextBuilder(@Nullable TraceContext parent, Sampler sa .spanId(nextId); } + boolean isNoop(TraceContext context) { + return noop.get() || !Boolean.TRUE.equals(context.sampled()); + } + TraceContext.Builder newContextBuilder(TraceContext parent, SamplingFlags samplingFlags) { return newContextBuilder(parent, samplerOverride(samplingFlags)).debug(samplingFlags.debug()); } diff --git a/brave/src/main/java/brave/internal/recorder/MutableSpan.java b/brave/src/main/java/brave/internal/recorder/MutableSpan.java index 43bd295242..2553e3c809 100644 --- a/brave/src/main/java/brave/internal/recorder/MutableSpan.java +++ b/brave/src/main/java/brave/internal/recorder/MutableSpan.java @@ -3,63 +3,55 @@ import brave.Clock; import brave.Span; import brave.internal.HexCodec; -import brave.internal.Nullable; import brave.propagation.TraceContext; import zipkin2.Endpoint; final class MutableSpan { final Clock clock; final zipkin2.Span.Builder span; - boolean finished; long timestamp; // Since this is not exposed, this class could be refactored later as needed to act in a pool // to reduce GC churn. This would involve calling span.clear and resetting the fields below. - MutableSpan(Clock clock, TraceContext context, Endpoint localEndpoint) { + MutableSpan(Clock clock, TraceContext context) { this.clock = clock; long parentId = context.parentIdAsLong(); this.span = zipkin2.Span.newBuilder() .traceId(context.traceIdString()) .parentId(parentId != 0L ? HexCodec.toLowerHex(parentId) : null) .id(HexCodec.toLowerHex(context.spanId())) - .debug(context.debug() ? true : null) - .localEndpoint(localEndpoint); - finished = false; + .debug(context.debug() ? true : null); } - MutableSpan start() { - return start(clock.currentTimeMicroseconds()); + void start() { + start(clock.currentTimeMicroseconds()); } - synchronized MutableSpan setShared() { + synchronized void setShared() { span.shared(true); - return this; } - synchronized MutableSpan start(long timestamp) { + synchronized void start(long timestamp) { span.timestamp(this.timestamp = timestamp); - return this; } - synchronized MutableSpan name(String name) { + synchronized void name(String name) { span.name(name); - return this; } - synchronized MutableSpan kind(Span.Kind kind) { + synchronized void kind(Span.Kind kind) { try { span.kind(zipkin2.Span.Kind.valueOf(kind.name())); } catch (IllegalArgumentException e) { // TODO: log } - return this; } - MutableSpan annotate(String value) { - return annotate(clock.currentTimeMicroseconds(), value); + void annotate(String value) { + annotate(clock.currentTimeMicroseconds(), value); } - synchronized MutableSpan annotate(long timestamp, String value) { + synchronized void annotate(long timestamp, String value) { if ("cs".equals(value)) { span.kind(zipkin2.Span.Kind.CLIENT).timestamp(this.timestamp = timestamp); } else if ("sr".equals(value)) { @@ -73,31 +65,24 @@ synchronized MutableSpan annotate(long timestamp, String value) { } else { span.addAnnotation(timestamp, value); } - return this; } - synchronized MutableSpan tag(String key, String value) { + synchronized void tag(String key, String value) { span.putTag(key, value); - return this; } - synchronized MutableSpan remoteEndpoint(Endpoint remoteEndpoint) { + synchronized void remoteEndpoint(Endpoint remoteEndpoint) { span.remoteEndpoint(remoteEndpoint); - return this; } /** Completes and reports the span */ - synchronized MutableSpan finish(@Nullable Long finishTimestamp) { - if (finished) return this; - finished = true; - - if (timestamp != 0 && finishTimestamp != null) { + synchronized void finish(long finishTimestamp) { + if (timestamp != 0L && finishTimestamp != 0L) { span.duration(Math.max(finishTimestamp - timestamp, 1)); } - return this; } - synchronized zipkin2.Span toSpan() { - return span.build(); + synchronized zipkin2.Span toSpan(Endpoint localEndpoint) { + return span.localEndpoint(localEndpoint).build(); } } diff --git a/brave/src/main/java/brave/internal/recorder/MutableSpanMap.java b/brave/src/main/java/brave/internal/recorder/MutableSpanMap.java index aca1f624fb..202457f2ec 100644 --- a/brave/src/main/java/brave/internal/recorder/MutableSpanMap.java +++ b/brave/src/main/java/brave/internal/recorder/MutableSpanMap.java @@ -63,7 +63,7 @@ MutableSpan getOrCreate(TraceContext context) { clock = new TickClock(this.clock.currentTimeMicroseconds(), System.nanoTime()); } - MutableSpan newSpan = new MutableSpan(clock, context, endpoint); + MutableSpan newSpan = new MutableSpan(clock, context); MutableSpan previousSpan = delegate.putIfAbsent(new RealKey(context, this), newSpan); if (previousSpan != null) return previousSpan; // lost race return newSpan; @@ -93,7 +93,7 @@ void reportOrphanedSpans() { if (value == null || noop.get()) continue; try { value.annotate(value.clock.currentTimeMicroseconds(), "brave.flush"); - reporter.report(value.toSpan()); + reporter.report(value.toSpan(endpoint)); } catch (RuntimeException e) { // don't crash the caller if there was a problem reporting an unrelated span. if (context != null && logger.isLoggable(Level.FINE)) { diff --git a/brave/src/main/java/brave/internal/recorder/Recorder.java b/brave/src/main/java/brave/internal/recorder/Recorder.java index e9cc6d2b97..dad08d8a48 100644 --- a/brave/src/main/java/brave/internal/recorder/Recorder.java +++ b/brave/src/main/java/brave/internal/recorder/Recorder.java @@ -12,6 +12,7 @@ /** Dispatches mutations on a span to a shared object per trace/span id. */ public final class Recorder { + final Endpoint endpoint; final MutableSpanMap spanMap; final Clock clock; final Reporter reporter; @@ -23,6 +24,7 @@ public Recorder( Reporter reporter, AtomicBoolean noop ) { + this.endpoint = localEndpoint; this.spanMap = new MutableSpanMap(localEndpoint, clock, reporter, noop); this.clock = clock; this.reporter = reporter; @@ -109,7 +111,7 @@ public void finish(TraceContext context) { if (span == null || noop.get()) return; synchronized (span) { span.finish(span.clock.currentTimeMicroseconds()); - reporter.report(span.toSpan()); + reporter.report(span.toSpan(endpoint)); } } @@ -119,7 +121,7 @@ public void finish(TraceContext context, long finishTimestamp) { if (span == null || noop.get()) return; synchronized (span) { span.finish(finishTimestamp); - reporter.report(span.toSpan()); + reporter.report(span.toSpan(endpoint)); } } @@ -133,8 +135,8 @@ public void flush(TraceContext context) { MutableSpan span = spanMap.remove(context); if (span == null || noop.get()) return; synchronized (span) { - span.finish(null); - reporter.report(span.toSpan()); + span.finish(0L); + reporter.report(span.toSpan(endpoint)); } } @@ -142,7 +144,7 @@ public void flush(TraceContext context) { public List snapshot() { List result = new ArrayList<>(); for (MutableSpan value : spanMap.delegate.values()) { - result.add(value.toSpan()); + result.add(value.toSpan(endpoint)); } return result; } diff --git a/brave/src/main/java/brave/propagation/SamplingFlags.java b/brave/src/main/java/brave/propagation/SamplingFlags.java index bffef2a3a0..6ccc3b6ba5 100644 --- a/brave/src/main/java/brave/propagation/SamplingFlags.java +++ b/brave/src/main/java/brave/propagation/SamplingFlags.java @@ -3,42 +3,81 @@ import brave.internal.Nullable; //@Immutable -public abstract class SamplingFlags { - public static final SamplingFlags EMPTY = new SamplingFlagsImpl(null, false); - public static final SamplingFlags SAMPLED = new SamplingFlagsImpl(true, false); - public static final SamplingFlags NOT_SAMPLED = new SamplingFlagsImpl(false, false); - public static final SamplingFlags DEBUG = new SamplingFlagsImpl(true, true); +public class SamplingFlags { + static final int FLAG_SAMPLED = 1 << 1; + static final int FLAG_SAMPLED_SET = 1 << 2; + static final int FLAG_DEBUG = 1 << 3; + + public static final SamplingFlags EMPTY = new SamplingFlags(0); + public static final SamplingFlags NOT_SAMPLED = new SamplingFlags(FLAG_SAMPLED_SET); + public static final SamplingFlags SAMPLED = new SamplingFlags(NOT_SAMPLED.flags | FLAG_SAMPLED); + public static final SamplingFlags DEBUG = new SamplingFlags(SAMPLED.flags | FLAG_DEBUG); + + final int flags; // bit field for sampled and debug + + SamplingFlags(int flags) { + this.flags = flags; + } /** * Should we sample this request or not? True means sample, false means don't, null means we defer * decision to someone further down in the stack. + * + *

Note: this is a uniform decision for the entire trace. Advanced sampling patterns can + * overlay this via {@link Propagation.Factory#isNoop(TraceContext)}. For example, a noop context + * usually implies sampled is false or unset. However, you can collect data anyway, locally for + * metrics, or to an aggregation stream. */ - @Nullable public abstract Boolean sampled(); + @Nullable public final Boolean sampled() { + return sampled(flags); + } /** * True is a request to store this span even if it overrides sampling policy. Defaults to false. */ - public abstract boolean debug(); + public final boolean debug() { + return debug(flags); + } + + @Override public String toString() { + return "SamplingFlags(sampled=" + sampled() + ", debug=" + debug() + ")"; + } public static final class Builder { - Boolean sampled; - boolean debug = false; + int flags = 0; // bit field for sampled and debug public Builder() { // public constructor instead of static newBuilder which would clash with TraceContext's } public Builder sampled(@Nullable Boolean sampled) { - this.sampled = sampled; + if (sampled == null) { + flags &= ~FLAG_SAMPLED_SET; + flags &= ~FLAG_SAMPLED; + return this; + } + flags |= FLAG_SAMPLED_SET; + if (sampled) { + flags |= FLAG_SAMPLED; + } else { + flags &= ~FLAG_SAMPLED; + } return this; } + /** Ensures sampled is set when debug is */ public Builder debug(boolean debug) { - this.debug = debug; - if (debug) sampled(true); + if (debug) { + flags |= FLAG_DEBUG; + flags |= FLAG_SAMPLED_SET; + flags |= FLAG_SAMPLED; + } else { + flags &= ~FLAG_DEBUG; + } return this; } + /** Allows you to create flags from a boolean value without allocating a builder instance */ public static SamplingFlags build(@Nullable Boolean sampled) { if (sampled != null) return sampled ? SAMPLED : NOT_SAMPLED; @@ -46,47 +85,18 @@ public static SamplingFlags build(@Nullable Boolean sampled) { } public SamplingFlags build() { - if (debug) return DEBUG; - return build(sampled); - } - } - - static final class SamplingFlagsImpl extends SamplingFlags { - final Boolean sampled; - final boolean debug; - - SamplingFlagsImpl(Boolean sampled, boolean debug) { - this.sampled = sampled; - this.debug = debug; - } - - @Override public Boolean sampled() { - return sampled; - } - - @Override public boolean debug() { - return debug; - } - - @Override public String toString() { - return "SamplingFlags(sampled=" + sampled + ", debug=" + debug + ")"; + return flags == 0 ? EMPTY : SamplingFlags.debug(flags) ? DEBUG + : SamplingFlags.sampled(flags) ? SAMPLED : NOT_SAMPLED; } } - SamplingFlags() { - } - - static final int FLAG_SAMPLED = 1 << 1; - static final int FLAG_SAMPLED_SET = 1 << 2; - static final int FLAG_DEBUG = 1 << 3; - - static Boolean sampled(int flags) { + private static Boolean sampled(int flags) { return (flags & FLAG_SAMPLED_SET) == FLAG_SAMPLED_SET ? (flags & FLAG_SAMPLED) == FLAG_SAMPLED : null; } - static boolean debug(int flags) { + private static boolean debug(int flags) { return (flags & FLAG_DEBUG) == FLAG_DEBUG; } } diff --git a/brave/src/main/java/brave/propagation/ThreadLocalSpan.java b/brave/src/main/java/brave/propagation/ThreadLocalSpan.java index 8d92ed1bcf..046ed57cab 100644 --- a/brave/src/main/java/brave/propagation/ThreadLocalSpan.java +++ b/brave/src/main/java/brave/propagation/ThreadLocalSpan.java @@ -5,7 +5,6 @@ import brave.Tracer.SpanInScope; import brave.Tracing; import brave.internal.Nullable; -import com.google.auto.value.AutoValue; import java.util.ArrayDeque; import java.util.Deque; @@ -75,21 +74,21 @@ * } * } */ -@AutoValue -public abstract class ThreadLocalSpan { +public class ThreadLocalSpan { /** * This uses the {@link Tracing#currentTracer()}, which means calls to {@link #next()} may return * null. Use this when you have no other means to get a reference to the tracer. For example, JDBC * connections, as they often initialize prior to the tracing component. */ - public static final ThreadLocalSpan CURRENT_TRACER = new ThreadLocalSpan() { + public static final ThreadLocalSpan CURRENT_TRACER = new ThreadLocalSpan(null) { @Override Tracer tracer() { return Tracing.currentTracer(); } }; public static ThreadLocalSpan create(Tracer tracer) { - return new AutoValue_ThreadLocalSpan(tracer); + if (tracer == null) throw new NullPointerException("tracer == null"); + return new ThreadLocalSpan(tracer); } /** @@ -103,7 +102,15 @@ public static ThreadLocalSpan create(Tracer tracer) { } }; - abstract Tracer tracer(); + final Tracer tracer; + + ThreadLocalSpan(Tracer tracer) { + this.tracer = tracer; + } + + Tracer tracer() { + return tracer; + } /** * Returns the {@link Tracer#nextSpan(TraceContextOrSamplingFlags)} or null if {@link #CURRENT_TRACER} @@ -113,7 +120,7 @@ public static ThreadLocalSpan create(Tracer tracer) { Tracer tracer = tracer(); if (tracer == null) return null; Span next = tracer.nextSpan(extracted); - SpanAndScope spanAndScope = SpanAndScope.create(next, tracer.withSpanInScope(next)); + SpanAndScope spanAndScope = new SpanAndScope(next, tracer.withSpanInScope(next)); currentSpanInScope.get().addFirst(spanAndScope); return next; } @@ -126,7 +133,7 @@ public static ThreadLocalSpan create(Tracer tracer) { Tracer tracer = tracer(); if (tracer == null) return null; Span next = tracer.nextSpan(); - SpanAndScope spanAndScope = SpanAndScope.create(next, tracer.withSpanInScope(next)); + SpanAndScope spanAndScope = new SpanAndScope(next, tracer.withSpanInScope(next)); currentSpanInScope.get().addFirst(spanAndScope); return next; } @@ -144,24 +151,37 @@ public static ThreadLocalSpan create(Tracer tracer) { SpanAndScope scope = currentSpanInScope.get().pollFirst(); if (scope == null) return currentSpan; - scope.scope().close(); - assert scope.span().equals(currentSpan) : - "Misalignment: scoped span " + scope.span() + " != current span " + currentSpan; + scope.scope.close(); + assert scope.span.equals(currentSpan) : + "Misalignment: scoped span " + scope.span + " != current span " + currentSpan; return currentSpan; } - ThreadLocalSpan() { - } - /** Allows state checks when nesting spans */ - @AutoValue - static abstract class SpanAndScope { - static SpanAndScope create(Span span, SpanInScope scope) { - return new AutoValue_ThreadLocalSpan_SpanAndScope(span, scope); + static final class SpanAndScope { + + final Span span; + final SpanInScope scope; + + SpanAndScope(Span span, SpanInScope scope) { + this.span = span; + this.scope = scope; } - abstract Span span(); + @Override public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof SpanAndScope)) return false; + SpanAndScope that = (SpanAndScope) o; + return span.equals(that.span) && scope.equals(that.scope); + } - abstract SpanInScope scope(); + @Override public int hashCode() { + int h = 1; + h *= 1000003; + h ^= span.hashCode(); + h *= 1000003; + h ^= scope.hashCode(); + return h; + } } } diff --git a/brave/src/main/java/brave/propagation/TraceContext.java b/brave/src/main/java/brave/propagation/TraceContext.java index 2d3ca23d6a..9648af5296 100644 --- a/brave/src/main/java/brave/propagation/TraceContext.java +++ b/brave/src/main/java/brave/propagation/TraceContext.java @@ -93,16 +93,6 @@ public long parentIdAsLong() { return parentId; } - /** {@inheritDoc} */ - @Override @Nullable public Boolean sampled() { - return sampled(flags); - } - - /** {@inheritDoc} */ - @Override public boolean debug() { - return debug(flags); - } - /** * Unique 8-byte identifier of this span within a trace. * @@ -240,15 +230,14 @@ public final TraceContext build() { } final long traceIdHigh, traceId, parentId, spanId; - final int flags; // bit field for sampled and debug final List extra; TraceContext(Builder builder) { // no external implementations + super(builder.flags); traceIdHigh = builder.traceIdHigh; traceId = builder.traceId; parentId = builder.parentId; spanId = builder.spanId; - flags = builder.flags; extra = builder.extra; } diff --git a/brave/src/main/java/brave/propagation/TraceIdContext.java b/brave/src/main/java/brave/propagation/TraceIdContext.java index 499b54d2f3..1029314dad 100644 --- a/brave/src/main/java/brave/propagation/TraceIdContext.java +++ b/brave/src/main/java/brave/propagation/TraceIdContext.java @@ -29,16 +29,6 @@ public long traceId() { return traceId; } - /** {@inheritDoc} */ - @Override @Nullable public Boolean sampled() { - return sampled(flags); - } - - /** {@inheritDoc} */ - @Override public boolean debug() { - return debug(flags); - } - public Builder toBuilder() { return new Builder(this); } @@ -108,12 +98,11 @@ public final TraceIdContext build() { } final long traceIdHigh, traceId; - final int flags; // bit field for sampled and debug TraceIdContext(Builder builder) { // no external implementations + super(builder.flags); traceIdHigh = builder.traceIdHigh; traceId = builder.traceId; - flags = builder.flags; } /** Only includes mandatory fields {@link #traceIdHigh()} and {@link #traceId()} */ diff --git a/brave/src/test/java/brave/internal/recorder/MutableSpanMapTest.java b/brave/src/test/java/brave/internal/recorder/MutableSpanMapTest.java index 85760b0f99..484f490896 100644 --- a/brave/src/test/java/brave/internal/recorder/MutableSpanMapTest.java +++ b/brave/src/test/java/brave/internal/recorder/MutableSpanMapTest.java @@ -25,8 +25,8 @@ @PrepareForTest({MutableSpanMap.class, MutableSpan.class}) public class MutableSpanMapTest { Endpoint endpoint = Platform.get().endpoint(); - List spans = new ArrayList(); - TraceContext context = TraceContext.newBuilder().traceId(1).spanId(2).build(); + List spans = new ArrayList<>(); + TraceContext context = TraceContext.newBuilder().traceId(1).spanId(2).sampled(true).build(); MutableSpanMap map = new MutableSpanMap(endpoint, () -> 0L, spans::add, new AtomicBoolean(false)); @Test @@ -180,6 +180,10 @@ public void reportOrphanedSpans_afterGC() { // We also expect the spans to have been reported assertThat(spans).flatExtracting(Span::annotations).extracting(Annotation::value) .containsExactly("brave.flush", "brave.flush"); + + // We also expect the spans reported to have the endpoint of the tracer + assertThat(spans).extracting(Span::localEndpoint) + .containsExactly(endpoint, endpoint); } @Test diff --git a/brave/src/test/java/brave/internal/recorder/MutableSpanTest.java b/brave/src/test/java/brave/internal/recorder/MutableSpanTest.java index 7f9c78cf57..810822e271 100644 --- a/brave/src/test/java/brave/internal/recorder/MutableSpanTest.java +++ b/brave/src/test/java/brave/internal/recorder/MutableSpanTest.java @@ -16,23 +16,13 @@ public class MutableSpanTest { Endpoint localEndpoint = Platform.get().endpoint(); TraceContext context = TraceContext.newBuilder().traceId(1).spanId(2).build(); - // zipkin needs one annotation or binary annotation so that the local endpoint can be read - @Test public void addsLocalEndpoint() { - MutableSpan span = newSpan(); - - span.start(1L); - span.finish(2L); - - assertThat(span.toSpan().localEndpoint()) - .isEqualTo(localEndpoint); - } - @Test public void minimumDurationIsOne() { MutableSpan span = newSpan(); - span.start(1L).finish(1L); + span.start(1L); + span.finish(1L); - assertThat(span.toSpan().duration()).isEqualTo(1L); + assertThat(toZipkinSpan(span).duration()).isEqualTo(1L); } @Test public void addsAnnotations() { @@ -42,7 +32,7 @@ public class MutableSpanTest { span.annotate(2L, "foo"); span.finish(2L); - assertThat(span.toSpan().annotations()) + assertThat(toZipkinSpan(span).annotations()) .containsOnly(Annotation.create(2L, "foo")); } @@ -68,7 +58,7 @@ private void finish(Kind braveKind, Span.Kind span2Kind) { span.start(1L); span.finish(2L); - Span span2 = span.toSpan(); + Span span2 = toZipkinSpan(span); assertThat(span2.annotations()).isEmpty(); assertThat(span2.timestamp()).isEqualTo(1L); assertThat(span2.duration()).isEqualTo(1L); @@ -90,7 +80,7 @@ private void finish(String start, String end, Span.Kind span2Kind) { span.annotate(1L, start); span.annotate(2L, end); - Span span2 = span.toSpan(); + Span span2 = toZipkinSpan(span); assertThat(span2.annotations()).isEmpty(); assertThat(span2.timestamp()).isEqualTo(1L); assertThat(span2.duration()).isEqualTo(1L); @@ -117,9 +107,9 @@ private void flush(Kind braveKind, Span.Kind span2Kind) { MutableSpan span = newSpan(); span.kind(braveKind); span.start(1L); - span.finish(null); + span.finish(0L); - Span span2 = span.toSpan(); + Span span2 = toZipkinSpan(span); assertThat(span2.annotations()).isEmpty(); assertThat(span2.timestamp()).isEqualTo(1L); assertThat(span2.duration()).isNull(); @@ -135,36 +125,50 @@ private void flush(Kind braveKind, Span.Kind span2Kind) { span.start(1L); span.finish(2L); - assertThat(span.toSpan().remoteEndpoint()) + assertThat(toZipkinSpan(span).remoteEndpoint()) .isEqualTo(endpoint); } // This prevents the server timestamp from overwriting the client one on the collector @Test public void reportsSharedStatus() { - MutableSpan span = new MutableSpan(() -> 0L, context.toBuilder().build(), localEndpoint); + MutableSpan span = new MutableSpan(() -> 0L, context); span.setShared(); span.start(1L); span.kind(SERVER); span.finish(2L); - assertThat(span.toSpan().shared()) + assertThat(toZipkinSpan(span).shared()) .isTrue(); } @Test public void flushUnstartedNeitherSetsTimestampNorDuration() { - Span flushed = newSpan().finish(null).toSpan(); - assertThat(flushed).extracting(Span::timestamp, Span::duration) - .allSatisfy(u -> assertThat(u).isNull()); + MutableSpan flushed = newSpan(); + flushed.finish(0L); + assertThat(flushed).extracting(s -> s.timestamp, s -> toZipkinSpan(s).durationAsLong()) + .allSatisfy(u -> assertThat(u).isEqualTo(0L)); } /** We can't compute duration unless we started the span in the same tracer. */ @Test public void finishUnstartedIsSameAsFlush() { - assertThat(newSpan().finish(2L).toSpan()) - .isEqualTo(newSpan().finish(null).toSpan()); + MutableSpan finishWithTimestamp = newSpan(); + finishWithTimestamp.finish(2L); + + MutableSpan finishWithNoTimestamp = newSpan(); + finishWithNoTimestamp.finish(0L); + + MutableSpan flush = newSpan(); + + assertThat(finishWithTimestamp) + .isEqualToComparingFieldByFieldRecursively(finishWithNoTimestamp) + .isEqualToComparingFieldByFieldRecursively(flush); } MutableSpan newSpan() { - return new MutableSpan(() -> 0L, context, localEndpoint); + return new MutableSpan(() -> 0L, context); + } + + Span toZipkinSpan(MutableSpan span) { + return span.toSpan(localEndpoint); } } diff --git a/brave/src/test/java/brave/internal/recorder/RecorderTest.java b/brave/src/test/java/brave/internal/recorder/RecorderTest.java index 48ef93b412..8197da106e 100644 --- a/brave/src/test/java/brave/internal/recorder/RecorderTest.java +++ b/brave/src/test/java/brave/internal/recorder/RecorderTest.java @@ -14,7 +14,7 @@ public class RecorderTest { Endpoint localEndpoint = Platform.get().endpoint(); List spans = new ArrayList<>(); - TraceContext context = TraceContext.newBuilder().traceId(1).spanId(2).build(); + TraceContext context = TraceContext.newBuilder().traceId(1).spanId(2).sampled(true).build(); Recorder recorder = new Recorder(localEndpoint, () -> 0L, spans::add, new AtomicBoolean(false)); @Test public void finish_calculatesDuration() { diff --git a/brave/src/test/java/brave/propagation/SamplingFlagsTest.java b/brave/src/test/java/brave/propagation/SamplingFlagsTest.java index 86ffd7f7c8..4fd2aa1938 100644 --- a/brave/src/test/java/brave/propagation/SamplingFlagsTest.java +++ b/brave/src/test/java/brave/propagation/SamplingFlagsTest.java @@ -41,4 +41,12 @@ public class SamplingFlagsTest { assertThat(flags.sampled()).isFalse(); assertThat(flags.debug()).isFalse(); } + + @Test public void nullSampled() { + SamplingFlags flags = new SamplingFlags.Builder().sampled(true).sampled(null).build(); + + assertThat(flags).isSameAs(SamplingFlags.EMPTY); + assertThat(flags.sampled()).isNull(); + assertThat(flags.debug()).isFalse(); + } } diff --git a/brave/src/test/java/brave/sampler/DeclarativeSamplerTest.java b/brave/src/test/java/brave/sampler/DeclarativeSamplerTest.java index a2ea9c5abc..1b919ee7ff 100644 --- a/brave/src/test/java/brave/sampler/DeclarativeSamplerTest.java +++ b/brave/src/test/java/brave/sampler/DeclarativeSamplerTest.java @@ -1,7 +1,7 @@ package brave.sampler; import brave.propagation.SamplingFlags; -import com.google.auto.value.AutoAnnotation; +import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import org.junit.Before; @@ -82,8 +82,19 @@ public class DeclarativeSamplerTest { boolean enabled() default true; } - // note: Unlike normal java annotations, auto-annotation do value-based equals and hashCode - @AutoAnnotation static Traced traced(float sampleRate, boolean enabled) { - return new AutoAnnotation_DeclarativeSamplerTest_traced(sampleRate, enabled); + static Traced traced(float sampleRate, boolean enabled) { + return new Traced() { + @Override public Class annotationType() { + return Traced.class; + } + + @Override public float sampleRate() { + return sampleRate; + } + + @Override public boolean enabled() { + return enabled; + } + }; } } diff --git a/instrumentation/grpc/pom.xml b/instrumentation/grpc/pom.xml index 570ff6b6e1..c491cc626c 100644 --- a/instrumentation/grpc/pom.xml +++ b/instrumentation/grpc/pom.xml @@ -24,12 +24,6 @@ ${grpc.version} provided - - - javax.annotation - javax.annotation-api - provided - ${project.groupId} brave-tests diff --git a/instrumentation/http/pom.xml b/instrumentation/http/pom.xml index 00c612dafd..35fb041a9d 100644 --- a/instrumentation/http/pom.xml +++ b/instrumentation/http/pom.xml @@ -17,17 +17,6 @@ - - com.google.auto.value - auto-value - provided - - - - javax.annotation - javax.annotation-api - provided - com.squareup.okhttp3 mockwebserver diff --git a/instrumentation/http/src/main/java/brave/http/HttpRuleSampler.java b/instrumentation/http/src/main/java/brave/http/HttpRuleSampler.java index 98db90abdf..a08d16790f 100644 --- a/instrumentation/http/src/main/java/brave/http/HttpRuleSampler.java +++ b/instrumentation/http/src/main/java/brave/http/HttpRuleSampler.java @@ -3,7 +3,6 @@ import brave.Tracing; import brave.internal.Nullable; import brave.sampler.ParameterizedSampler; -import com.google.auto.value.AutoValue; import java.util.ArrayList; import java.util.List; @@ -60,18 +59,34 @@ public HttpSampler build() { String method = adapter.method(request); String path = adapter.path(request); if (method == null || path == null) return null; // use default if we couldn't parse - return sampler.sample(MethodAndPath.create(method, path)).sampled(); + return sampler.sample(new MethodAndPath(method, path)).sampled(); } - @AutoValue - static abstract class MethodAndPath { - static MethodAndPath create(String method, String path) { - return new AutoValue_HttpRuleSampler_MethodAndPath(method, path); + static final class MethodAndPath { + + final String method; + final String path; + + MethodAndPath(String method, String path) { + this.method = method; + this.path = path; } - abstract String method(); + @Override public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof MethodAndPath)) return false; + MethodAndPath that = (MethodAndPath) o; + return method.equals(that.method) && path.equals(that.path); + } - abstract String path(); + @Override public int hashCode() { + int h = 1; + h *= 1000003; + h ^= method.hashCode(); + h *= 1000003; + h ^= path.hashCode(); + return h; + } } static final class MethodAndPathRule extends ParameterizedSampler.Rule { @@ -85,8 +100,8 @@ static final class MethodAndPathRule extends ParameterizedSampler.RuleWhen present, a link from {@link Tracing.Builder#localServiceName(String)} to this name will - * increment for each traced client call. + *

When present, a link from {@link Tracing.Builder#localServiceName(String)} to this name + * will increment for each traced client call. * *

As this is endpoint-specific, it is typical to create a scoped instance of {@linkplain * HttpTracing} to assign this value. @@ -54,7 +40,9 @@ public static Builder newBuilder(Tracing tracing) { * @see HttpClientAdapter#parseServerAddress(Object, Endpoint.Builder) * @see brave.Span#remoteEndpoint(Endpoint) */ - public abstract String serverName(); + public String serverName() { + return serverName; + } /** * Scopes this component for a client of the indicated server. @@ -65,7 +53,9 @@ public HttpTracing clientOf(String serverName) { return toBuilder().serverName(serverName).build(); } - public abstract HttpServerParser serverParser(); + public HttpServerParser serverParser() { + return serverParser; + } /** * Returns an overriding sampling decision for a new trace. Defaults to ignore the request and use @@ -75,24 +65,83 @@ public HttpTracing clientOf(String serverName) { * making an http request as a part of booting your application. You may want to opt-out of * tracing client requests that did not originate from a server request. */ - public abstract HttpSampler clientSampler(); + public HttpSampler clientSampler() { + return clientSampler; + } /** * Returns an overriding sampling decision for a new trace. Defaults to ignore the request and use * the {@link HttpSampler#TRACE_ID trace ID instead}. * - *

This decision happens when trace IDs were not in headers, or a sampling decision has not yet - * been made. For example, if a trace is already in progress, this function is not called. You can - * implement this to skip paths that you never want to trace. + *

This decision happens when trace IDs were not in headers, or a sampling decision has not + * yet been made. For example, if a trace is already in progress, this function is not called. You + * can implement this to skip paths that you never want to trace. */ - public abstract HttpSampler serverSampler(); + public HttpSampler serverSampler() { + return serverSampler; + } - public abstract Builder toBuilder(); + public Builder toBuilder() { + return new Builder(this); + } + + final Tracing tracing; + final HttpClientParser clientParser; + final String serverName; + final HttpServerParser serverParser; + final HttpSampler clientSampler, serverSampler; + + HttpTracing(Builder builder) { + this.tracing = builder.tracing; + this.clientParser = builder.clientParser; + this.serverName = builder.serverName; + this.serverParser = builder.serverParser; + this.clientSampler = builder.clientSampler; + this.serverSampler = builder.serverSampler; + } + + public static final class Builder { + Tracing tracing; + HttpClientParser clientParser; + String serverName; + HttpServerParser serverParser; + HttpSampler clientSampler, serverSampler; + + Builder(Tracing tracing) { + if (tracing == null) throw new NullPointerException("tracing == null"); + final ErrorParser errorParser = tracing.errorParser(); + this.tracing = tracing; + this.serverName = ""; + // override to re-use any custom error parser from the tracing component + this.clientParser = new HttpClientParser() { + @Override protected ErrorParser errorParser() { + return errorParser; + } + }; + this.serverParser = new HttpServerParser() { + @Override protected ErrorParser errorParser() { + return errorParser; + } + }; + this.clientSampler = HttpSampler.TRACE_ID; + this.serverSampler(HttpSampler.TRACE_ID); + } + + Builder(HttpTracing source) { + this.tracing = source.tracing; + this.clientParser = source.clientParser; + this.serverName = source.serverName; + this.serverParser = source.serverParser; + this.clientSampler = source.clientSampler; + this.serverSampler = source.serverSampler; + } - @AutoValue.Builder - public static abstract class Builder { /** @see HttpTracing#tracing() */ - public abstract Builder tracing(Tracing tracing); + public Builder tracing(Tracing tracing) { + if (tracing == null) throw new NullPointerException("tracing == null"); + this.tracing = tracing; + return this; + } /** * Overrides the tagging policy for http client spans. @@ -100,7 +149,17 @@ public static abstract class Builder { * @see HttpParser#errorParser() for advice when making custom types * @see HttpTracing#clientParser() */ - public abstract Builder clientParser(HttpClientParser clientParser); + public Builder clientParser(HttpClientParser clientParser) { + if (clientParser == null) throw new NullPointerException("clientParser == null"); + this.clientParser = clientParser; + return this; + } + + Builder serverName(String serverName) { + if (serverName == null) throw new NullPointerException("serverName == null"); + this.serverName = serverName; + return this; + } /** * Overrides the tagging policy for http client spans. @@ -108,22 +167,29 @@ public static abstract class Builder { * @see HttpParser#errorParser() for advice when making custom types * @see HttpTracing#serverParser() */ - public abstract Builder serverParser(HttpServerParser serverParser); + public Builder serverParser(HttpServerParser serverParser) { + if (serverParser == null) throw new NullPointerException("serverParser == null"); + this.serverParser = serverParser; + return this; + } /** @see HttpTracing#clientSampler() */ - public abstract Builder clientSampler(HttpSampler clientSampler); - - /** @see HttpTracing#serverSampler() */ - public abstract Builder serverSampler(HttpSampler serverSampler); - - public abstract HttpTracing build(); + public Builder clientSampler(HttpSampler clientSampler) { + if (clientSampler == null) throw new NullPointerException("clientSampler == null"); - abstract Builder serverName(String serverName); + this.clientSampler = clientSampler; + return this; + } - Builder() { + /** @see HttpTracing#serverSampler() */ + public Builder serverSampler(HttpSampler serverSampler) { + if (serverSampler == null) throw new NullPointerException("serverSampler == null"); + this.serverSampler = serverSampler; + return this; } - } - HttpTracing() { // intentionally hidden constructor + public HttpTracing build() { + return new HttpTracing(this); + } } } diff --git a/instrumentation/jaxrs2/pom.xml b/instrumentation/jaxrs2/pom.xml index 3a016c3efb..58ca3bdd8d 100644 --- a/instrumentation/jaxrs2/pom.xml +++ b/instrumentation/jaxrs2/pom.xml @@ -31,6 +31,7 @@ javax.annotation javax.annotation-api provided + 1.3.1 diff --git a/pom.xml b/pom.xml index 7e002631cd..18f8a7f99d 100755 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,6 @@ 3.9.0 2.0.0-beta.5 1.10.19 - 1.3.1 2.25.1 1.20 @@ -213,16 +212,6 @@ spring-test ${spring.version} - - com.google.auto.value - auto-value - 1.5.3 - - - javax.annotation - javax.annotation-api - ${javax.annotation-api.version} - org.apache.commons commons-lang3