StructuredCoder extends Coder<T> { @Override public String toString() { StringBuilder builder = new StringBuilder(); String s = getClass().getName(); builder.append(s.substring(s.lastIndexOf('.') + 1)); List<? extends Coder<?>> componentCoders = getComponents(); if (!componentCoders.isEmpty()) { builder.append('('); boolean first = true; for (Coder<?> componentCoder : componentCoders) { if (first) { first = false; } else { builder.append(','); } builder.append(componentCoder.toString()); } builder.append(')'); } return builder.toString(); } protected  StructuredCoder(); List<? extends Coder<?>> getComponents(); @Override boolean equals(@Nullable Object o); @Override int hashCode(); @Override String toString();  }
@Test public void testToString() { Assert.assertThat( new ObjectIdentityBooleanCoder().toString(), CoreMatchers.equalTo("StructuredCoderTest$ObjectIdentityBooleanCoder")); ObjectIdentityBooleanCoder coderWithArgs = new ObjectIdentityBooleanCoder() { @Override public List<? extends Coder<?>> getCoderArguments() { return ImmutableList.<Coder<?>>builder() .add(BigDecimalCoder.of(), BigIntegerCoder.of()) .build(); } }; Assert.assertThat( coderWithArgs.toString(), CoreMatchers.equalTo("StructuredCoderTest$1(BigDecimalCoder,BigIntegerCoder)")); }