DoFnSignatures { @VisibleForTesting static DoFnSignature.BundleMethod analyzeStartBundleMethod( ErrorReporter errors, TypeDescriptor<? extends DoFn<?, ?>> fnT, Method m, TypeDescriptor<?> inputT, TypeDescriptor<?> outputT, FnAnalysisContext fnContext) { errors.checkArgument(void.class.equals(m.getReturnType()), "Must return void"); Type[] params = m.getGenericParameterTypes(); MethodAnalysisContext methodContext = MethodAnalysisContext.create(); for (int i = 0; i < params.length; ++i) { Parameter extraParam = analyzeExtraParameter( errors, fnContext, methodContext, fnT, ParameterDescription.of( m, i, fnT.resolveType(params[i]), Arrays.asList(m.getParameterAnnotations()[i])), inputT, outputT); methodContext.addParameter(extraParam); } for (Parameter parameter : methodContext.getExtraParameters()) { checkParameterOneOf(errors, parameter, ALLOWED_START_BUNDLE_PARAMETERS); } return DoFnSignature.BundleMethod.create(m, methodContext.extraParameters); } private  DoFnSignatures(); static DoFnSignature signatureForDoFn(FnT fn); static synchronized DoFnSignature getSignature(Class<FnT> fn); static StateSpec<?> getStateSpecOrThrow(
      StateDeclaration stateDeclaration, DoFn<?, ?> target); static TimerSpec getTimerSpecOrThrow(
      TimerDeclaration timerDeclaration, DoFn<?, ?> target); static TimerSpec getTimerFamilySpecOrThrow(
      TimerFamilyDeclaration timerFamilyDeclaration, DoFn<?, ?> target); static boolean isSplittable(DoFn<?, ?> doFn); static boolean isStateful(DoFn<?, ?> doFn); static boolean usesMapState(DoFn<?, ?> doFn); static boolean usesSetState(DoFn<?, ?> doFn); static boolean usesOrderedListState(DoFn<?, ?> doFn); static boolean usesValueState(DoFn<?, ?> doFn); static boolean usesBagState(DoFn<?, ?> doFn); static boolean usesWatermarkHold(DoFn<?, ?> doFn); static boolean usesTimers(DoFn<?, ?> doFn); static boolean usesState(DoFn<?, ?> doFn); static boolean requiresTimeSortedInput(DoFn<?, ?> doFn);  }
@Test public void testBadExtraContext() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("int is not a valid context parameter"); DoFnSignatures.analyzeStartBundleMethod( errors(), TypeDescriptor.of(FakeDoFn.class), new DoFnSignaturesTestUtils.AnonymousMethod() { void method(DoFn<Integer, String>.StartBundleContext c, int n) {} }.getMethod(), TypeDescriptor.of(Integer.class), TypeDescriptor.of(String.class), FnAnalysisContext.create()); }