public static <FnT extends DoFn<?, ?>> DoFnSignature getSignature(Class<FnT> fn) {
    return signatureCache.computeIfAbsent(fn, DoFnSignatures::parseSignature);
  }
@Test
  public void testStateIdDuplicate() throws Exception {
    thrown.expect(IllegalArgumentException.class);
    thrown.expectMessage("Duplicate");
    thrown.expectMessage("StateId");
    thrown.expectMessage("my-id");
    thrown.expectMessage("myfield1");
    thrown.expectMessage("myfield2");
    thrown.expectMessage(not(mentionsTimers()));
    DoFnSignatures.getSignature(
        new DoFn<KV<String, Integer>, Long>() {

          @StateId("my-id")
          private final StateSpec<ValueState<Integer>> myfield1 =
              StateSpecs.value(VarIntCoder.of());

          @StateId("my-id")
          private final StateSpec<ValueState<Long>> myfield2 = StateSpecs.value(VarLongCoder.of());

          @ProcessElement
          public void foo(ProcessContext context) {}
        }.getClass());
  }