@Override
 public void encountered(Class<?> proxyType, Method method, Object[] args) {
   if (PropertyResolver.MUTATORS.isValid(method)) {
     String propertyName =
         config.getDestinationNameTransformer().transform(method.getName(), NameableType.METHOD);
     propertyInfo.add(PropertyInfoRegistry.mutatorFor(proxyType, method, config, propertyName));
     argument = args.length == 1 ? args[0] : null;
     if (argument != null && argument == builder.source) builder.errors.missingSource();
     builder.saveMapping();
   } else if (PropertyResolver.ACCESSORS.isValid(method)) {
     // Find mutator corresponding to accessor
     Mutator mutator =
         TypeInfoRegistry.typeInfoFor(proxyType, config)
             .mutatorForAccessorMethod(method.getName());
     if (mutator != null) propertyInfo.add(mutator);
     else builder.errors.missingMutatorForAccessor(method);
   } else builder.errors.invalidDestinationMethod(method);
 }
  /**
   * Sets a mapped or converted destination value in the last mapped mutator for the given {@code
   * mapping}. The final destination value is resolved by walking the {@code mapping}'s mutator
   * chain and obtaining each destination value in the chain either from the cache, from a
   * corresponding accessor, from a provider, or by instantiation, in that order.
   */
  @SuppressWarnings({"unchecked", "rawtypes"})
  private void setDestinationValue(
      MappingContextImpl<?, ?> context,
      MappingContextImpl<Object, Object> propertyContext,
      MappingImpl mapping,
      Converter<Object, Object> converter) {
    Object destination = context.getDestination();
    List<Mutator> mutatorChain = (List<Mutator>) mapping.getDestinationProperties();
    StringBuilder destPathBuilder = new StringBuilder();

    for (int i = 0; i < mutatorChain.size(); i++) {
      Mutator mutator = mutatorChain.get(i);
      destPathBuilder.append(mutator.getName()).append('.');
      String destPath = destPathBuilder.toString();

      // Handle last mutator in chain
      if (i == mutatorChain.size() - 1) {
        // Final destination value
        Object destinationValue = null;

        if (converter != null) {
          // Obtain from accessor on provided destination
          if (context.providedDestination) {
            Accessor accessor =
                TypeInfoRegistry.typeInfoFor(destination.getClass(), configuration)
                    .getAccessors()
                    .get(mutator.getName());
            if (accessor != null) {
              Object intermediateDest = accessor.getValue(destination);
              propertyContext.setDestination(intermediateDest);
            }
          }

          destinationValue = convert(propertyContext, converter);
        } else if (propertyContext.getSource() != null) destinationValue = map(propertyContext);

        context.destinationCache.put(destPath, destinationValue);
        mutator.setValue(
            destination,
            destinationValue == null
                ? Primitives.defaultValue(mutator.getType())
                : destinationValue);
        if (destinationValue == null) context.shadePath(mapping.getPath());
      } else {
        // Obtain from cache
        Object intermediateDest = context.destinationCache.get(destPath);

        if (intermediateDest != null) {
          mutator.setValue(destination, intermediateDest);
        } else {
          // Obtain from circular destinations
          if (!context.intermediateDestinations.isEmpty()) {
            for (Object intermediateDestination : context.intermediateDestinations) {
              // Match intermediate destinations to mutator by type
              if (intermediateDestination.getClass().equals(mutator.getType())) {
                intermediateDest = intermediateDestination;
                mutator.setValue(destination, intermediateDest);
                break;
              }
            }
          }

          if (intermediateDest == null) {
            // Obtain from accessor on provided destination
            if (context.providedDestination) {
              Accessor accessor =
                  TypeInfoRegistry.typeInfoFor(destination.getClass(), configuration)
                      .getAccessors()
                      .get(mutator.getName());
              if (accessor != null) intermediateDest = accessor.getValue(destination);
            }

            // Obtain from new instance
            if (intermediateDest == null) {
              if (propertyContext.getSource() == null) return;

              Provider<?> globalProvider = configuration.getProvider();
              if (globalProvider != null)
                intermediateDest =
                    globalProvider.get(
                        new ProvisionRequestImpl(context.parentSource(), mutator.getType()));
              else intermediateDest = instantiate(mutator.getType(), context.errors);
              if (intermediateDest == null) return;

              mutator.setValue(destination, intermediateDest);
            }
          }

          context.destinationCache.put(destPath, intermediateDest);
        }

        destination = intermediateDest;
      }
    }
  }