/** * Verifies that a non-splittable {@link DoFn} does not declare any methods that only make sense * for splittable {@link DoFn}: {@link DoFn.GetInitialRestriction}, {@link DoFn.SplitRestriction}, * {@link DoFn.NewTracker}, {@link DoFn.GetRestrictionCoder}. */ private static void verifyUnsplittableMethods(ErrorReporter errors, DoFnSignature signature) { List<String> forbiddenMethods = new ArrayList<>(); if (signature.getInitialRestriction() != null) { forbiddenMethods.add("@" + DoFn.GetInitialRestriction.class.getSimpleName()); } if (signature.splitRestriction() != null) { forbiddenMethods.add("@" + DoFn.SplitRestriction.class.getSimpleName()); } if (signature.newTracker() != null) { forbiddenMethods.add("@" + DoFn.NewTracker.class.getSimpleName()); } if (signature.getRestrictionCoder() != null) { forbiddenMethods.add("@" + DoFn.GetRestrictionCoder.class.getSimpleName()); } errors.checkArgument( forbiddenMethods.isEmpty(), "Non-splittable, but defines methods: %s", forbiddenMethods); }
private static DoFnSignature.LifecycleMethod analyzeLifecycleMethod( ErrorReporter errors, Method m) { errors.checkArgument(void.class.equals(m.getReturnType()), "Must return void"); errors.checkArgument(m.getGenericParameterTypes().length == 0, "Must take zero arguments"); return DoFnSignature.LifecycleMethod.create(m); }
@Nullable private static Method findAnnotatedMethod( ErrorReporter errors, Class<? extends Annotation> anno, Class<?> fnClazz, boolean required) { Collection<Method> matches = declaredMethodsWithAnnotation(anno, fnClazz, DoFn.class); if (matches.isEmpty()) { errors.checkArgument(!required, "No method annotated with @%s found", anno.getSimpleName()); return null; } // If we have at least one match, then either it should be the only match // or it should be an extension of the other matches (which came from parent // classes). Method first = matches.iterator().next(); for (Method other : matches) { errors.checkArgument( first.getName().equals(other.getName()) && Arrays.equals(first.getParameterTypes(), other.getParameterTypes()), "Found multiple methods annotated with @%s. [%s] and [%s]", anno.getSimpleName(), format(first), format(other)); } ErrorReporter methodErrors = errors.forMethod(anno, first); // We need to be able to call it. We require it is public. methodErrors.checkArgument((first.getModifiers() & Modifier.PUBLIC) != 0, "Must be public"); // And make sure its not static. methodErrors.checkArgument((first.getModifiers() & Modifier.STATIC) == 0, "Must not be static"); return first; }
errors.checkArgument(DoFn.class.isAssignableFrom(fnClass), "Must be subtype of DoFn"); signatureBuilder.setFnClass(fnClass); for (Method onTimerMethod : onTimerMethods) { String id = onTimerMethod.getAnnotation(DoFn.OnTimer.class).value(); errors.checkArgument( fnContext.getTimerDeclarations().containsKey(id), "Callback %s is for undeclared timer %s", errors.checkArgument( timerDecl.field().getDeclaringClass().equals(onTimerMethod.getDeclaringClass()), "Callback %s is for timer %s declared in a different class %s." errors.checkArgument( onTimerMethodMap.containsKey(decl.id()), "No callback registered via %s for timer %s",
methodErrors.checkArgument( paramT.equals(inputT), "@Element argument must have type %s", inputT); return Parameter.elementParameter(paramT); methodErrors.checkArgument( rawType.equals(Instant.class), "@Timestamp argument must have type org.joda.time.Instant."); return Parameter.paneInfoParameter(); } else if (rawType.equals(DoFn.ProcessContext.class)) { paramErrors.checkArgument( paramT.equals(expectedProcessContextT), "ProcessContext argument must have type %s", return Parameter.processContext(); } else if (rawType.equals(DoFn.OnTimerContext.class)) { paramErrors.checkArgument( paramT.equals(expectedOnTimerContextT), "OnTimerContext argument must have type %s", return Parameter.onTimerContext(); } else if (BoundedWindow.class.isAssignableFrom(rawType)) { methodErrors.checkArgument( !methodContext.hasWindowParameter(), "Multiple %s parameters", if (!schemaRowReceiver) { TypeDescriptor<?> expectedReceiverT = outputReceiverTypeOf(outputT); paramErrors.checkArgument(
errors.forMethod(DoFn.GetInitialRestriction.class, getInitialRestriction.targetMethod()); TypeDescriptor<?> restrictionT = getInitialRestriction.restrictionT(); getInitialRestrictionErrors.checkArgument( restrictionT.equals(newTracker.restrictionT()), "Uses restriction type %s, but @%s method %s uses restriction type %s", errors.forMethod(DoFn.GetInitialRestriction.class, getInitialRestriction.targetMethod()); TypeDescriptor<?> restrictionT = getInitialRestriction.restrictionT(); processElementErrors.checkArgument( processElement.trackerT().getRawType().equals(RestrictionTracker.class), "Has tracker type %s, but the DoFn's tracker type must be of type RestrictionTracker.", getInitialRestrictionErrors.checkArgument( getRestrictionCoder.coderT().isSubtypeOf(coderTypeOf(restrictionT)), "Uses restriction type %s, but @%s method %s returns %s " getInitialRestrictionErrors.checkArgument( splitRestriction.restrictionT().equals(restrictionT), "Uses restriction type %s, but @%s method %s uses restriction type %s",
if (supertype.getRawType().isAnnotationPresent(DoFn.BoundedPerElement.class) || supertype.getRawType().isAnnotationPresent(DoFn.UnboundedPerElement.class)) { errors.checkArgument( isBounded == null, "Both @%s and @%s specified", errors.checkArgument( isBounded == null, "Non-splittable, but annotated as @"
TypeDescriptor<?> outputT, FnAnalysisContext fnContext) { errors.checkArgument( void.class.equals(m.getReturnType()) || DoFn.ProcessContinuation.class.equals(m.getReturnType()),
TypeDescriptor<?> outputT, FnAnalysisContext fnContext) { errors.checkArgument(void.class.equals(m.getReturnType()), "Must return void");
TypeDescriptor<?> outputT, FnAnalysisContext fnContext) { errors.checkArgument(void.class.equals(m.getReturnType()), "Must return void");
@VisibleForTesting static DoFnSignature.SplitRestrictionMethod analyzeSplitRestrictionMethod( ErrorReporter errors, TypeDescriptor<? extends DoFn> fnT, Method m, TypeDescriptor<?> inputT) { // Method is of the form: // @SplitRestriction // void splitRestriction(InputT element, RestrictionT restriction); errors.checkArgument(void.class.equals(m.getReturnType()), "Must return void"); Type[] params = m.getGenericParameterTypes(); errors.checkArgument(params.length == 3, "Must have exactly 3 arguments"); errors.checkArgument( fnT.resolveType(params[0]).equals(inputT), "First argument must be the element type %s", formatType(inputT)); TypeDescriptor<?> restrictionT = fnT.resolveType(params[1]); TypeDescriptor<?> receiverT = fnT.resolveType(params[2]); TypeDescriptor<?> expectedReceiverT = outputReceiverTypeOf(restrictionT); errors.checkArgument( receiverT.equals(expectedReceiverT), "Third argument must be %s, but is %s", formatType(expectedReceiverT), formatType(receiverT)); return DoFnSignature.SplitRestrictionMethod.create(m, restrictionT); }
@VisibleForTesting static DoFnSignature.BundleMethod analyzeFinishBundleMethod( ErrorReporter errors, TypeDescriptor<? extends DoFn<?, ?>> fnT, Method m, TypeDescriptor<?> inputT, TypeDescriptor<?> outputT) { errors.checkArgument(void.class.equals(m.getReturnType()), "Must return void"); TypeDescriptor<?> expectedContextT = doFnFinishBundleContextTypeOf(inputT, outputT); Type[] params = m.getGenericParameterTypes(); errors.checkArgument( params.length == 0 || (params.length == 1 && fnT.resolveType(params[0]).equals(expectedContextT)), "Must take a single argument of type %s", formatType(expectedContextT)); return DoFnSignature.BundleMethod.create(m); }
@VisibleForTesting static DoFnSignature.GetInitialRestrictionMethod analyzeGetInitialRestrictionMethod( ErrorReporter errors, TypeDescriptor<? extends DoFn> fnT, Method m, TypeDescriptor<?> inputT) { // Method is of the form: // @GetInitialRestriction // RestrictionT getInitialRestriction(InputT element); Type[] params = m.getGenericParameterTypes(); errors.checkArgument( params.length == 1 && fnT.resolveType(params[0]).equals(inputT), "Must take a single argument of type %s", formatType(inputT)); return DoFnSignature.GetInitialRestrictionMethod.create( m, fnT.resolveType(m.getGenericReturnType())); }
@VisibleForTesting static DoFnSignature.NewTrackerMethod analyzeNewTrackerMethod( ErrorReporter errors, TypeDescriptor<? extends DoFn> fnT, Method m) { // Method is of the form: // @NewTracker // TrackerT newTracker(RestrictionT restriction); Type[] params = m.getGenericParameterTypes(); errors.checkArgument(params.length == 1, "Must have a single argument"); TypeDescriptor<?> restrictionT = fnT.resolveType(params[0]); TypeDescriptor<?> trackerT = fnT.resolveType(m.getGenericReturnType()); TypeDescriptor<?> expectedTrackerT = restrictionTrackerTypeOf(restrictionT); errors.checkArgument( trackerT.isSubtypeOf(expectedTrackerT), "Returns %s, but must return a subtype of %s", formatType(trackerT), formatType(expectedTrackerT)); return DoFnSignature.NewTrackerMethod.create(m, restrictionT, trackerT); }
@VisibleForTesting static DoFnSignature.BundleMethod analyzeStartBundleMethod( ErrorReporter errors, TypeDescriptor<? extends DoFn<?, ?>> fnT, Method m, TypeDescriptor<?> inputT, TypeDescriptor<?> outputT) { errors.checkArgument(void.class.equals(m.getReturnType()), "Must return void"); TypeDescriptor<?> expectedContextT = doFnStartBundleContextTypeOf(inputT, outputT); Type[] params = m.getGenericParameterTypes(); errors.checkArgument( params.length == 0 || (params.length == 1 && fnT.resolveType(params[0]).equals(expectedContextT)), "Must take a single argument of type %s", formatType(expectedContextT)); return DoFnSignature.BundleMethod.create(m); }
@VisibleForTesting static DoFnSignature.GetRestrictionCoderMethod analyzeGetRestrictionCoderMethod( ErrorReporter errors, TypeDescriptor<? extends DoFn> fnT, Method m) { errors.checkArgument(m.getParameterTypes().length == 0, "Must have zero arguments"); TypeDescriptor<?> resT = fnT.resolveType(m.getGenericReturnType()); errors.checkArgument( resT.isSubtypeOf(TypeDescriptor.of(Coder.class)), "Must return a Coder, but returns %s", formatType(resT)); return DoFnSignature.GetRestrictionCoderMethod.create(m, resT); }