MutableSpan implements Cloneable { @Nullable static String normalizeIdField(String field, @Nullable String id, boolean isNullable) { if (id == null) { if (isNullable) return null; throw new NullPointerException(field + " == null"); } int length = id.length(); if (length == 0) { if (isNullable) return null; throw new IllegalArgumentException(field + " is empty"); } int desiredLength = field.equals("traceId") && length > 16 ? 32 : 16; int existingPadding = validateHexAndReturnPadding(field, id, desiredLength); if (desiredLength == 32 && existingPadding >= 16) { return id.substring(16); } return length == desiredLength ? id : padLeft(id, desiredLength, existingPadding); } MutableSpan();  MutableSpan(TraceContext context, @Nullable MutableSpan defaults);  MutableSpan(MutableSpan toCopy); @Deprecated boolean isEmpty(); String traceId(); void traceId(String traceId); @Nullable String localRootId(); void localRootId(String localRootId); @Nullable String parentId(); void parentId(@Nullable String parentId); String id(); void id(String id); @Nullable String name(); void name(@Nullable String name); long startTimestamp(); void startTimestamp(long startTimestamp); long finishTimestamp(); void finishTimestamp(long finishTimestamp); Kind kind(); void kind(@Nullable Kind kind); @Nullable String localServiceName(); void localServiceName(@Nullable String localServiceName); @Nullable String localIp(); boolean localIp(@Nullable String localIp); int localPort(); void localPort(int localPort); @Nullable String remoteServiceName(); void remoteServiceName(@Nullable String remoteServiceName); @Nullable String remoteIp(); void remoteIp(@Nullable String remoteIp); int remotePort(); void remotePort(int remotePort); boolean remoteIpAndPort(@Nullable String remoteIp, int remotePort); Throwable error(); void error(@Nullable Throwable error); boolean debug(); void setDebug(); void unsetDebug(); boolean shared(); void setShared(); void unsetShared(); int annotationCount(); long annotationTimestampAt(int i); String annotationValueAt(int i); Collection<Map.Entry<Long, String>> annotations(); void forEachAnnotation(AnnotationConsumer<T> annotationConsumer, T target); void forEachAnnotation(AnnotationUpdater annotationUpdater); boolean containsAnnotation(String value); void annotate(long timestamp, String value); int tagCount(); String tagKeyAt(int i); String tagValueAt(int i); Map<String, String> tags(); @Nullable String tag(String key); @Nullable String removeTag(String key); void forEachTag(TagConsumer<T> tagConsumer, T target); void forEachTag(TagUpdater tagUpdater); void tag(String key, String value); @Override String toString(); @Override int hashCode(); @Override boolean equals(Object o);  }
@Test public void normalizeIdField_truncates64BitZeroPrefix() { assertThat(normalizeIdField("traceId", "0000000000000000000000000000162e", false)) .isEqualTo("000000000000162e"); }
@Test public void normalizeIdField_padsTo64() { assertThat(normalizeIdField("spanId", "162e", false)) .isEqualTo("000000000000162e"); }
@Test public void normalizeIdField_padsTo128() { assertThat(normalizeIdField("traceId", "4d2000000000000162e", false)) .isEqualTo("00000000000004d2000000000000162e"); }
@Test public void normalizeIdField_badCharacters() { assertThatThrownBy(() -> normalizeIdField("traceId", "000-0000000004d20000000ss000162e", false)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("traceId should be lower-hex encoded with no prefix"); }