static Optional<ResultReturner> of(Type returnType, Method method, int functionIndex) {
            Type parameterType = method.getGenericParameterTypes()[functionIndex];

            QualifiedType<?> targetType = QualifiedType.of(
                GenericTypes.findGenericParameter(parameterType, Function.class, 1)
                    .orElseThrow(() -> new IllegalStateException(
                        format("Cannot reflect Function<T, R> element type R in method function parameter '%s'", parameterType))));

            if (!QualifiedType.of(returnType).equals(targetType)) {
                throw new IllegalArgumentException(format("Function<T, R> argument R ('%s') for %s must match the function return type ('%s')",
                    targetType, method, returnType));
            }

            QualifiedType<?> elementType = QualifiedType.of(
                GenericTypes.findGenericParameter(parameterType, Function.class, 0)
                    .orElseThrow(() -> new IllegalStateException(
                        format("Cannot reflect Function<T, R> element type T in method function parameter '%s'", parameterType))))
                .withAnnotations(new Qualifiers().findFor(method.getParameters()[functionIndex]));

            Type type = elementType.getType();

            if (GenericTypes.isSuperType(Iterator.class, type)) {
                // special case: Function<Iterator<T>, R>
                if (GenericTypes.getErasedType(type) == Iterator.class) {
                    return getIteratorFunction(functionIndex, elementType.mapType(t -> GenericTypes.findGenericParameter(t, Iterator.class)
                        .orElseThrow(() -> new IllegalStateException(format("Couldn't find Iterator type on '%s'", elementType)))));
                }
                throw new IllegalArgumentException(format("Function argument for %s can not use subtype '%s' of Iterator!", method, type));

            } else if (GenericTypes.isSuperType(Stream.class, type)) {
                // special case: Function<Stream<T>, R>
                if (GenericTypes.getErasedType(type) == Stream.class) {
                    return getStreamFunction(functionIndex, elementType.mapType(t -> GenericTypes.findGenericParameter(t, Stream.class)
                        .orElseThrow(() -> new IllegalStateException(format("Couldn't find Stream type on '%s'", elementType)))));
                }
                throw new IllegalArgumentException(format("Function argument for %s can not use subtype '%s' of Stream!", method, type));

            } else if (GenericTypes.isSuperType(Iterable.class, type)) {
                // special case: Function<Iterable<T>, R>
                if (GenericTypes.getErasedType(type) == Iterable.class) {
                    return getIterableFunction(functionIndex, elementType.mapType(t -> GenericTypes.findGenericParameter(t, Iterable.class)
                        .orElseThrow(() -> new IllegalStateException(format("Couldn't find Iterable type on '%s'", elementType)))));
                }
                throw new IllegalArgumentException(format("Function argument for %s can not use subtype '%s' of Iterable!", method, type));

            } else {
                return Optional.empty();
            }
        }
Inspect a Method for a {@link Consumer} to execute for each produced row.

@param method the method called
@return a ResultReturner that invokes the consumer and does not return a value
sqlobject/src/main/java/org/jdbi/v3/sqlobject/statement/internal/ResultReturner.java