@Nullable private static TypeDescriptor<? extends BoundedWindow> getWindowType( TypeDescriptor<?> fnClass, Method method) { Type[] params = method.getGenericParameterTypes(); for (Type param : params) { TypeDescriptor<?> paramT = fnClass.resolveType(param); if (BoundedWindow.class.isAssignableFrom(paramT.getRawType())) { return (TypeDescriptor<? extends BoundedWindow>) paramT; } } return null; }
@Nullable private static TypeDescriptor<?> getTrackerType(TypeDescriptor<?> fnClass, Method method) { Type[] params = method.getGenericParameterTypes(); for (Type param : params) { TypeDescriptor<?> paramT = fnClass.resolveType(param); if (RestrictionTracker.class.isAssignableFrom(paramT.getRawType())) { return paramT; } } return null; }
@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())); }
private void checkMap(String context, TypeDescriptor<?> type, Schema schema) { if (!isSubtypeOf(type, SortedMap.class)) { reportError(context, "%s may not be deterministically ordered", type); } // Avro (currently) asserts that all keys are strings. // In case that changes, we double check that the key was a string: Class<?> keyType = type.resolveType(Map.class.getTypeParameters()[0]).getRawType(); if (!String.class.equals(keyType)) { reportError(context, "map keys should be Strings, but was %s", keyType); } recurse(context, type.resolveType(Map.class.getTypeParameters()[1]), schema.getValueType()); }
private void checkRecord(TypeDescriptor<?> type, Schema schema) { // For a record, we want to make sure that all the fields are deterministic. Class<?> clazz = type.getRawType(); for (Schema.Field fieldSchema : schema.getFields()) { Field field = getField(clazz, fieldSchema.name()); String fieldContext = field.getDeclaringClass().getName() + "#" + field.getName(); if (field.isAnnotationPresent(AvroEncode.class)) { reportError( fieldContext, "Custom encoders may be non-deterministic -- remove @AvroEncode"); continue; } if (!IndexedRecord.class.isAssignableFrom(field.getType()) && field.isAnnotationPresent(AvroSchema.class)) { // TODO: We should be able to support custom schemas on POJO fields, but we shouldn't // need to, so we just allow it in the case of IndexedRecords. reportError( fieldContext, "Custom schemas are only supported for subtypes of IndexedRecord."); continue; } TypeDescriptor<?> fieldType = type.resolveType(field.getGenericType()); recurse(fieldContext, fieldType, fieldSchema.schema()); } }
/** Returns the {@link TypeDescriptor} for the type encoded. */ @Experimental(Kind.CODER_TYPE_ENCODING) public TypeDescriptor<T> getEncodedTypeDescriptor() { return (TypeDescriptor<T>) TypeDescriptor.of(getClass()).resolveType(new TypeDescriptor<T>() {}.getType()); }
@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); }
@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.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); }
outputFormatValueClass.getRawType(), TypeDescriptor.class.getSimpleName(), inputTypeDescriptor.resolveType(KV.class.getTypeParameters()[0]), inputTypeDescriptor.resolveType(KV.class.getTypeParameters()[1]));
m, i, fnClass.resolveType(params[i]), Arrays.asList(m.getParameterAnnotations()[i])), inputT,
m, i, fnClass.resolveType(params[i]), Arrays.asList(m.getParameterAnnotations()[i])), inputT,
@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); }
TypeDescriptor.of(fnClazz).resolveType(unresolvedStateType);
m, i, fnClass.resolveType(params[i]), Arrays.asList(m.getParameterAnnotations()[i])), inputT,
Coder<?> typeArgumentCoder = typeArgumentCoders.get(i); verifyCompatible( typeArgumentCoder, candidateDescriptor.resolveType(typeArguments[i]).getType()); } catch (IncompatibleCoderException exn) { throw new IncompatibleCoderException(
private void checkArray(String context, TypeDescriptor<?> type, Schema schema) { TypeDescriptor<?> elementType = null; if (type.isArray()) { // The type is an array (with ordering)-> deterministic iff the element is deterministic. elementType = type.getComponentType(); } else if (isSubtypeOf(type, Collection.class)) { if (isSubtypeOf(type, List.class, SortedSet.class)) { // Ordered collection -> deterministic iff the element is deterministic elementType = type.resolveType(Collection.class.getTypeParameters()[0]); } else { // Not an ordered collection -> not deterministic reportError(context, "%s may not be deterministically ordered", type); return; } } else { // If it was an unknown type encoded as an array, be conservative and assume // that we don't know anything about the order. reportError(context, "encoding %s as an ARRAY was unexpected", type); return; } // If we get here, it's either a deterministically-ordered Collection, or // an array. Either way, the type is deterministic iff the element type is // deterministic. recurse(context, elementType, schema.getElementType()); }