public static <InputT, OutputT> DoFnInvoker<InputT, OutputT> invokerFor(
      DoFn<InputT, OutputT> fn) {
    return ByteBuddyDoFnInvokerFactory.only().newByteBuddyInvoker(fn);
  }
@Test
  public void testSplittableDoFnWithHasDefaultMethods() throws Exception {
    class MockFn extends DoFn<String, String> {
      @ProcessElement
      public void processElement(
          ProcessContext c,
          RestrictionTracker<RestrictionWithBoundedDefaultTracker, Void> tracker,
          WatermarkEstimator<WatermarkEstimatorStateWithDefaultWatermarkEstimator>
              watermarkEstimator) {}

      @GetInitialRestriction
      public RestrictionWithBoundedDefaultTracker getInitialRestriction(@Element String element) {
        return null;
      }

      @GetInitialWatermarkEstimatorState
      public WatermarkEstimatorStateWithDefaultWatermarkEstimator
          getInitialWatermarkEstimatorState() {
        return null;
      }
    }

    MockFn fn = mock(MockFn.class);
    DoFnInvoker<String, String> invoker = DoFnInvokers.invokerFor(fn);

    CoderRegistry coderRegistry = CoderRegistry.createDefault();
    coderRegistry.registerCoderProvider(
        CoderProviders.fromStaticMethods(
            RestrictionWithBoundedDefaultTracker.class, CoderForDefaultTracker.class));
    coderRegistry.registerCoderForClass(
        WatermarkEstimatorStateWithDefaultWatermarkEstimator.class,
        new CoderForWatermarkEstimatorStateWithDefaultWatermarkEstimator());
    assertThat(
        invoker.<RestrictionWithBoundedDefaultTracker>invokeGetRestrictionCoder(coderRegistry),
        instanceOf(CoderForDefaultTracker.class));
    assertThat(
        invoker.invokeGetWatermarkEstimatorStateCoder(coderRegistry),
        instanceOf(CoderForWatermarkEstimatorStateWithDefaultWatermarkEstimator.class));
    invoker.invokeSplitRestriction(
        new FakeArgumentProvider<String, String>() {
          @Override
          public String element(DoFn<String, String> doFn) {
            return "blah";
          }

          @Override
          public Object restriction() {
            return "foo";
          }

          @Override
          public OutputReceiver<String> outputReceiver(DoFn<String, String> doFn) {
            return new DoFn.OutputReceiver<String>() {
              private boolean invoked;

              @Override
              public void output(String output) {
                assertFalse(invoked);
                invoked = true;
                assertEquals("foo", output);
              }

              @Override
              public void outputWithTimestamp(String output, Instant instant) {
                assertFalse(invoked);
                invoked = true;
                assertEquals("foo", output);
              }

              @Override
              public void outputWindowedValue(
                  String output,
                  Instant timestamp,
                  Collection<? extends BoundedWindow> windows,
                  PaneInfo paneInfo) {
                assertFalse(invoked);
                invoked = true;
                assertEquals("foo", output);
              }
            };
          }
        });
    assertEquals(stop(), invoker.invokeProcessElement(mockArgumentProvider));
    assertThat(
        invoker.invokeNewTracker(
            new FakeArgumentProvider<String, String>() {
              @Override
              public Object restriction() {
                return new RestrictionWithBoundedDefaultTracker();
              }
            }),
        instanceOf(BoundedDefaultTracker.class));
    assertThat(
        invoker.invokeNewWatermarkEstimator(
            new FakeArgumentProvider<String, String>() {
              @Override
              public Object watermarkEstimatorState() {
                return new WatermarkEstimatorStateWithDefaultWatermarkEstimator();
              }
            }),
        instanceOf(DefaultWatermarkEstimator.class));
  }