/**
   * Applies the configured {@link UriComponentsContributor}s to the given {@link
   * UriComponentsBuilder}.
   *
   * @param builder will never be {@literal null}.
   * @param invocation will never be {@literal null}.
   * @return
   */
  protected UriComponentsBuilder applyUriComponentsContributer(
      UriComponentsBuilder builder, MethodInvocation invocation) {

    MethodParameters parameters = new MethodParameters(invocation.getMethod());
    Iterator<Object> parameterValues = Arrays.asList(invocation.getArguments()).iterator();

    for (MethodParameter parameter : parameters.getParameters()) {
      Object parameterValue = parameterValues.next();
      for (UriComponentsContributor contributor : uriComponentsContributors) {
        if (contributor.supportsParameter(parameter)) {
          contributor.enhance(builder, parameter, parameterValue);
        }
      }
    }

    return builder;
  }
  /*
   * (non-Javadoc)
   * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.Object)
   */
  @Override
  public ControllerLinkBuilder linkTo(Object invocationValue) {

    Assert.isInstanceOf(LastInvocationAware.class, invocationValue);
    LastInvocationAware invocations = (LastInvocationAware) invocationValue;

    MethodInvocation invocation = invocations.getLastInvocation();
    Iterator<Object> classMappingParameters = invocations.getObjectParameters();
    Method method = invocation.getMethod();

    String mapping = DISCOVERER.getMapping(method);
    UriComponentsBuilder builder = ControllerLinkBuilder.getBuilder().path(mapping);

    UriTemplate template = new UriTemplate(mapping);
    Map<String, Object> values = new HashMap<String, Object>();

    Iterator<String> names = template.getVariableNames().iterator();
    while (classMappingParameters.hasNext()) {
      values.put(names.next(), classMappingParameters.next());
    }

    for (BoundMethodParameter parameter : PATH_VARIABLE_ACCESSOR.getBoundParameters(invocation)) {
      values.put(parameter.getVariableName(), parameter.asString());
    }

    for (BoundMethodParameter parameter : REQUEST_PARAM_ACCESSOR.getBoundParameters(invocation)) {

      Object value = parameter.getValue();
      String key = parameter.getVariableName();

      if (value instanceof Collection) {
        for (Object element : (Collection<?>) value) {
          builder.queryParam(key, element);
        }
      } else {
        builder.queryParam(key, parameter.asString());
      }
    }

    UriComponents components =
        applyUriComponentsContributer(builder, invocation).buildAndExpand(values);
    return new ControllerLinkBuilder(UriComponentsBuilder.fromUri(components.toUri()));
  }