class PropertyReferenceCollector {
  private final InheritingConfiguration config;
  private final ExplicitMappingBuilder.MappingOptions options;
  private final List<Accessor> accessors;
  private final List<Mutator> mutators;

  // This field will be set with a value if the mapping is map from source
  private Class<?> sourceType;
  // This field will be set with a value if the mapping is map from constant
  private Object constant;

  private final Errors errors;
  private final Errors proxyErrors;

  public static <S, D> List<Accessor> collect(TypeMapImpl<S, D> typeMap, TypeSafeSourceGetter<S, ?> sourceGetter) {<FILL_FUNCTION_BODY>}

  PropertyReferenceCollector(InheritingConfiguration config, ExplicitMappingBuilder.MappingOptions options) {
    this.config = config;
    this.options = options;
    this.accessors = new ArrayList<Accessor>();
    this.mutators = new ArrayList<Mutator>();
    this.errors = new Errors();
    this.proxyErrors = new Errors();
  }

  public final class SourceInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
      visitSource(proxy.getClass(), method);
      if (Void.class.isAssignableFrom(method.getReturnType()))
        return null;
      try {
        return ProxyFactory.proxyFor(resolveReturnType(method), this, proxyErrors);
      } catch (ErrorsException e) {
        return null;
      }
    }
  }

  public final class DestinationInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
      visitDestination(proxy.getClass(), method);
      if (Void.class.isAssignableFrom(method.getReturnType()))
        return null;
      try {
        return ProxyFactory.proxyFor(resolveReturnType(method), this, proxyErrors);
      } catch (ErrorsException e) {
        return null;
      }
    }
  }

  private static Class<?> resolveReturnType(Method method) {
    Accessor accessor = new MethodAccessor(method.getDeclaringClass(), method, method.getName());
    return accessor.getType();
  }

  SourceInterceptor newSourceInterceptor() {
    return new SourceInterceptor();
  }

  DestinationInterceptor newDestinationInterceptor() {
    return new DestinationInterceptor();
  }

  private void visitSource(Class<?> type, Method method) {
    if (PropertyInfoResolver.ACCESSORS.isValid(method)) {
      String propertyName = config.getSourceNameTransformer().transform(method.getName(),
          NameableType.METHOD);
      accessors.add(PropertyInfoRegistry.accessorFor(type, method, config,
          propertyName));
    } else
      errors.addMessage("Illegal SourceGetter method: %s.%s", type.getName(), method.getName());
  }

  private void visitDestination(Class<?> type, Method method) {
    if (PropertyInfoResolver.MUTATORS.isValid(method)) {
      String propertyName = config.getDestinationNameTransformer().transform(method.getName(),
          NameableType.METHOD);
      mutators.add(PropertyInfoRegistry.mutatorFor(type, method, config,
          propertyName));
    } else if (PropertyInfoResolver.ACCESSORS.isValid(method)) {
      Mutator mutator = TypeInfoRegistry.typeInfoFor(type, config).mutatorForAccessorMethod(
          method.getName());
      if (mutator != null)
        mutators.add(mutator);
      else
        errors.addMessage("No setter found: %s.%s", type.getName(), method.getName());
    } else
      errors.addMessage("Illegal DestinationSetter method: %s.%s", type.getName(), method.getName());
  }

  MappingImpl collect() {
    if (mutators.isEmpty())
      errors.addMessage("Illegal DestinationSetter defined");
    if (options.skipType == 1 && options.condition != null && accessors.isEmpty())
      errors.addMessage("Source properties must be provided when conditional skip, please use when().skip(sourceGetter, destinationSetter) instead");
    errors.throwConfigurationExceptionIfErrorsExist();
    if (sourceType != null)
      return new SourceMappingImpl(sourceType, new ArrayList<Mutator>(mutators), options);
    if (accessors.isEmpty())
      return new ConstantMappingImpl(constant, new ArrayList<Mutator>(mutators), options);
    return new PropertyMappingImpl(new ArrayList<Accessor>(accessors), new ArrayList<Mutator>(mutators), options);
  }

  void reset() {
    mutators.clear();
    accessors.clear();
    options.reset();
    sourceType = null;
    constant = null;
  }

  public Errors getErrors() {
    return errors;
  }

  Errors getProxyErrors() {
    return proxyErrors;
  }

  void mapFromSource(Class<?> sourceType) {
    this.sourceType = sourceType;
  }

  void mapFromConstant(Object constant) {
    this.constant = constant;
  }

  boolean isNoSourceGetter() {
    return accessors.isEmpty();
  }
}

    PropertyReferenceCollector collector = new PropertyReferenceCollector(typeMap.configuration, null);
    try {
      S source = ProxyFactory.proxyFor(typeMap.getSourceType(), collector.newSourceInterceptor(), collector.getProxyErrors());
      Object sourceProperty = sourceGetter.get(source);
      if (source == sourceProperty)
        collector.mapFromSource(typeMap.getSourceType());
      if (collector.isNoSourceGetter())
        collector.mapFromConstant(sourceProperty);
    } catch (NullPointerException e) {
      if (collector.getProxyErrors().hasErrors())
        throw collector.getProxyErrors().toException();
      throw e;
    } catch (ErrorsException e) {
      throw e.getErrors().toConfigurationException();
    }
    return collector.accessors;
  
<no_super_class>