@SuppressWarnings("rawtypes")
static final Map<Class<?>, Provider<Collection<?>>> COLLECTION_KINDS =
    ImmutableMap.<Class<?>, Provider<Collection<?>>> builder()
    .put(List.class, new Provider<Collection<?>>() {
      public Collection<?> get() {
        return new ArrayList();
      }
    })
    .put(Set.class, new Provider<Collection<?>>() {
      public Collection<?> get() {
        return new HashSet();
      }
    })
    .put(Collection.class, new Provider<Collection<?>>() {
      public Collection<?> get() {
        return new ArrayList();
      }
    })
    .build();
 static Errors cannotAnnotateOptionWithOptional(Errors errors, Type genericParameterType) {
  return errors.addMessage(
      "cannot annotate %s with @Optional",
      genericParameterType.toString());
}
 static Errors cannotSpecifyDefaultValueAndConstant(Errors errors, Optional annotation) {
  return errors.addMessage(
      "cannot specify both a default constant and a default value %s",
      annotation.toString().replaceFirst(Optional.class.getName(), Optional.class.getSimpleName()));
}
 static Errors constantHasIncompatibleType(Errors errors, Class<?> container, String constant) {
  return errors.addMessage("constant %s of incompatible type",
      localConstantQualifier(container, constant));
}
 static Errors constantIsNotStaticFinal(Errors errors, Class<?> container, String constant) {
  return errors.addMessage("constant %s is not static final",
      localConstantQualifier(container, constant));
}
 static Errors enumHasAmbiguousNames(Errors errors, Class<? extends Enum<?>> clazz) {
  return errors.addMessage(
      "enum %s has ambiguous names",
      clazz.getName());
}
 static Errors illegalConstructor(Errors errors, Class<?> klass, String message) {
  return errors.addMessage(
      "%s has an illegal constructor%s",
      klass, message == null ? "" : ": " + message);
}
 @SuppressWarnings("rawtypes")
static Errors incorrectBoundForConverter(
    Errors errors,
    Type targetType,
    Class<? extends Converter> converterClass,
    Type producedType) {
  return errors.addMessage(
      "the converter %2$s, mentioned on %1$s using @%4$s, does not produce " +
      "instances of %1$s. It produces %3$s.",
      targetType,
      converterClass,
      producedType,
      ConvertedBy.class.getSimpleName());
}
 static Errors incorrectDefaultValue(Errors errors, String value, RuntimeException e) {
  return errors.addMessage(
      "%s: For default value \"%s\"",
      e.getClass().getName(), value);
}
 static Errors moreThanOneConstructor(Errors errors, Class<?> klass) {
  return errors.addMessage(
      "%s has more than one constructors",
      klass);
}
 static Errors moreThanOneConstructorWithInstantiate(Errors errors, Class<?> klass) {
  return errors.addMessage(
      "%s has more than one constructor annotated with @%s",
      klass,
      Instantiate.class.getSimpleName());
}
 static Errors moreThanOneMatchingFunction(Errors errors, Type type) {
  return errors.addMessage(
      "%s has more than one matching function",
      type);
}
 static Errors noConverterForType(Errors errors, Type type) {
  return errors.addMessage(
      "no converter for %s",
      type);
}
 static Errors noSuchField(Errors errors, String fieldName) {
  return errors.addMessage(
      "no such field %s",
      fieldName);
}
 static Errors optionalLiteralParameterMustHaveDefault(Errors errors, int parameterNum) {
  return errors.addMessage(
      "parameter %s: opetional literal parameters must have a default value",
      parameterNum + 1);
}
 static Errors unableToGetField(Errors errors, String fieldName, SecurityException e) {
  return errors.addMessage(
      "unable to get field %s due to security violation",
      fieldName);
}
 static Errors unableToInstantiate(Errors errors, Class<?> klass, Exception e) {
  return errors.addMessage(
      "unable to instantiate %s due to %s",
      klass,
      e.getCause());
}
 static Errors unableToResolveConstant(Errors errors, Class<?> container, String constant) {
  return unableToResolveFullyQualifiedConstant(
      errors, localConstantQualifier(container, constant));
}
 static Errors unableToResolveFullyQualifiedConstant(Errors errors, String constant) {
  return errors.addMessage(
      "unable to resolve constant %s", constant);
}
 static final Converter<Boolean> C_BOOLEAN = new ConverterWithToString<Boolean>() {
  @Override
  public Boolean fromString(String representation) {
    String trimmed = representation.trim();
    if ("true".equalsIgnoreCase(trimmed)) {
      return true;
    }
    if ("false".equalsIgnoreCase(trimmed)) {
      return false;
    }
    throw new IllegalArgumentException(String.format("representation is not a valid boolean : %s", representation));
  }
};
 static final Converter<Byte> C_BYTE = new ConverterWithToString<Byte>() {
  @Override
  public Byte fromString(String representation) {
    return Byte.parseByte(representation);
  }
};
 static final Converter<Character> C_CHAR = new ConverterWithToString<Character>() {
  @Override
  public Character fromString(String representation) {
    if (representation.length() != 1) {
      throw new IllegalArgumentException(format(
          "For input string: \"%s\"", representation));
    }
    return representation.charAt(0);
  }
};
 static final Converter<Double> C_DOUBLE = new ConverterWithToString<Double>() {
  @Override
  public Double fromString(String representation) {
    return Double.parseDouble(representation);
  }
};
 static final Converter<Float> C_FLOAT = new ConverterWithToString<Float>() {
  @Override
  public Float fromString(String representation) {
    return Float.parseFloat(representation);
  }
};
 static final Converter<Integer> C_INT = new ConverterWithToString<Integer>() {
  @Override
  public Integer fromString(String representation) {
    return Integer.parseInt(representation);
  }
};
 static final Converter<Long> C_LONG = new ConverterWithToString<Long>() {
  @Override
  public Long fromString(String representation) {
    return Long.parseLong(representation);
  }
};
 static final Converter<Short> C_SHORT = new ConverterWithToString<Short>() {
  @Override
  public Short fromString(String representation) {
    return Short.parseShort(representation);
  }
};
 static final Converter<String> C_STRING = new ConverterWithToString<String>() {
  @Override
  public String fromString(String representation) {
    return representation;
  }
};
 public class Errors {

  // null or [E :: L] where L is any list
  private List<String> messages;

  public Errors addMessage(String message, Object... values) {
    if (messages == null) {
      messages = newArrayList();
    }
    String formattedMessage = format(message, values);
    if (!messages.contains(formattedMessage)) {
      messages.add(formattedMessage);
    }
    return this;
  }

  public Errors addErrors(Errors errors) {
    if (errors.messages == null) {
      return this;
    }
    for (String message : errors.messages) {
      addMessage(message);
    }
    return this;
  }

  public List<String> getMessages() {
    if (messages == null) {
      return emptyList();
    }
    return ImmutableList.copyOf(messages);
  }

  public void throwIfHasErrors() {
    if (messages != null) {
      throw new RuntimeException(toString());
    }
  }

  public int size() {
    return messages == null ? 0 : messages.size();
  }

  public boolean hasErrors() {
    return 0 < size();
  }

  @Override
  public int hashCode() {
    return messages == null ? EMPTY_LIST.hashCode() : messages.hashCode();
  }

  @Override
  public boolean equals(Object that) {
    if (this == that) {
      return true;
    }
    if (!(that instanceof Errors)) {
      return false;
    }
    return this.messages == null ?
        ((Errors) that).messages == null :
          this.messages.equals(((Errors) that).messages);
  }

  @Override
  public String toString() {
    if (messages == null) {
      return "no errors";
    }
    StringBuilder buf = new StringBuilder();
    int num = 1;
    String separator = "";
    for (String message : messages) {
      buf.append(separator);
      buf.append(num);
      buf.append(") ");
      buf.append(message);
      num++;
      separator = "\n\n";
    }
    return buf.toString();
  }

} public abstract class Option<T> implements Iterable<T> {

  /** The singleton representing none.
   */
  private final static Option<?> NONE = new Option<Object>() {

    @Override
    public Iterator<Object> iterator() {
      return new AbstractIterator<Object>() {
        @Override
        protected Object computeNext() {
          return endOfData();
        }
      };
    }

    @Override
    public Object getOrNull() {
      return null;
    };

    @Override
    public Object getOrElse(Object defaultValue) {
      return defaultValue;
    }

    @Override
    public Object getOrElse(Thunk<Object> defaultValue) {
      return defaultValue.get();
    }

    @Override
    public Object getOrThrow() {
      return getOrThrow(new IllegalArgumentException());
    }

    @Override
    public Object getOrThrow(String message) {
      return getOrThrow(new IllegalArgumentException(message));
    }

    @Override
    public <E extends Throwable> Object getOrThrow(E e) throws E {
      throw e;
    }

    @Override
    public String toStringOr(String defaultValue) {
      return defaultValue;
    }

    @Override
    public boolean isEmpty() {
      return true;
    }
    
    @Override
    public <U> U visit(OptionVisitor<Object, U> visitor) {
      return visitor.caseNone();
    }

    @Override
    public <U> Option<U> transform(Function<Object, U> function) {
      return Option.none();
    }

    @Override
    public Set<Object> asSet() {
      return Collections.emptySet();
    }

    @Override
    public int hashCode() {
      return 0;
    }

    @Override
    public boolean equals(Object that) {
      return this == that;
    }

    @Override
    public String toString() {
      return "Option.None";
    }

  };

  /** The object representing some result.
   */
  private final static class Some<U> extends Option<U> {

    private final U u;

    private Some(U u) {
      Preconditions.checkNotNull(u);
      this.u = u;
    }

    @Override
    public Iterator<U> iterator() {
      return new AbstractIterator<U>() {
        private boolean produce = true;
        @Override
        protected U computeNext() {
          if (produce) {
            produce = false;
            return u;
          } else {
            return endOfData();
          }
        }
      };
    }

    @Override
    public U getOrNull() {
      return u;
    }

    @Override
    public U getOrElse(U defaultValue) {
      return u;
    }

    @Override
    public U getOrElse(Thunk<U> defaultValue) {
      return u;
    }

    @Override
    public U getOrThrow() {
      return u;
    }

    @Override
    public U getOrThrow(String message) {
      return u;
    }

    @Override
    public <E extends Throwable> U getOrThrow(E e) throws E {
      return u;
    }

    @Override
    public String toStringOr(String defaultValue) {
      return u.toString();
    }

    @Override
    public boolean isEmpty() {
      return false;
    }

    @Override
    public <V> V visit(OptionVisitor<? super U, V> visitor) {
      return visitor.caseSome(u);
    }
    
    @Override
    public <V> Option<V> transform(Function<? super U, V> function) {
      return Option.of(function.apply(u));
    }

    @Override
    public Set<U> asSet() {
      return Collections.singleton(u);
    }

    @Override
    public int hashCode() {
      return u.hashCode();
    }

    @Override
    public boolean equals(Object that) {
      if (this == that) {
        return true;
      }
      if (!(that instanceof Some<?>)) {
        return false;
      }
      return this.u.equals(((Some<?>) that).u);
    }

    @Override
    public String toString() {
      return format("Option.Some(%s)", u);
    }

  }

  /**
   * If the option is nonempty returns its value, otherwise returns
   * {@code null}.
   */
  public abstract T getOrNull();

  /**
   * If the option is nonempty returns its value, otherwise returns
   * {@code defaultValue}. Note that {@code defaultValue} is eagerly evaluated.
   */
  public abstract T getOrElse(T defaultValue);

  /**
   * If the option is nonempty returns its value, otherwise returns
   * {@code defaultValue}. The {@code defaultValue} is lazily evaluated.
   */
  public abstract T getOrElse(Thunk<T> defaultValue);

  /**
   * Gets the value of this option. If this is a Some(T) the value is returned,
   * otherwise an {@link IllegalArgumentException} is thrown.
   */
  public abstract T getOrThrow();

  /**
   * Gets the value of this option. If this is a Some(T) the value is returned,
   * otherwise an {@link IllegalArgumentException} is thrown with the specifed
   * message.
   */
  public abstract T getOrThrow(String message);

  /**
   * Returns its value if not empty, otherwise throws {@code e}.
   */
  public abstract <E extends Throwable> T getOrThrow(E e) throws E;

  public abstract String toStringOr(String defaultValue);

  /**
   * Returns {@code true} if the option is the {@code None} value.
   */
  public abstract boolean isEmpty();

  /**
   * Returns {@code true} if the option is a {@code Some(...)}.
   */
  public boolean isDefined() {
    return !isEmpty();
  }

  /**
   * Visits the {@code Option} using the {@code visitor}.
   */
  public abstract <U> U visit(OptionVisitor<? super T, U> visitor);

  public abstract <U> Option<U> transform(Function<? super T, U> function);

  public abstract Set<T> asSet();
  
  /**
   * Gets the none object for the given type.
   *
   * Note: using a freely parameterized type {@code T} with an unchecked warning
   * allows to simulate a bottom type in Java.
   */
  @SuppressWarnings("unchecked")
  public static <T> Option<T> none() {
    return (Option<T>) NONE;
  }

  /**
   * Gets the some object wrapping the given value.
   */
  public static <T> Option<T> some(T t) {
    return new Option.Some<T>(t);
  }

  /**
   * Wraps anything.
   *
   * @param <T>
   * @param t
   * @return if null, none(), some(t) otherwise
   */
  public static <T> Option<T> of(T t) {
    return t == null ? Option.<T>none() : some(t);
  }

}
 public class Types {

  /**
   * Verifies that {@code b} is an instance of the type scheme {@code a}.
   */
  public static boolean isInstance(Type a, Type b) {
    if (a instanceof Class<?>) {
      return a.equals(b);
    } else if (a instanceof GenericArrayType) {
      if (b instanceof GenericArrayType) {
        return isInstance(
            ((GenericArrayType) a).getGenericComponentType(),
            ((GenericArrayType) b).getGenericComponentType());
      } else {
        return false;
      }
    } else if (a instanceof ParameterizedType) {
      if (!(b instanceof ParameterizedType)) {
        return false;
      }
      ParameterizedType parameterizedTypeA = (ParameterizedType) a;
      ParameterizedType parameterizedTypeB = (ParameterizedType) b;
      Type[] actualTypeArgumentsA = parameterizedTypeA.getActualTypeArguments();
      Type[] actualTypeArgumentsB = parameterizedTypeB.getActualTypeArguments();
      if (!parameterizedTypeA.getRawType().equals(parameterizedTypeB.getRawType()) ||
          actualTypeArgumentsA.length != actualTypeArgumentsB.length) {
        return false;
      }
      for (int i = 0; i < actualTypeArgumentsA.length; i++) {
        if (!isInstance(actualTypeArgumentsA[i], actualTypeArgumentsB[i])) {
          return false;
        }
      }
      return true;
    } else if (a instanceof TypeVariable<?>) {
      TypeVariable<?> typeVariable = (TypeVariable<?>) a;
      for (Type bound : typeVariable.getBounds()) {
        return isAssignableFrom(bound, b);
      }
      return true;
    } else if (a instanceof WildcardType) {
      WildcardType wildcardType = (WildcardType) a;
      for (Type lowerBound : wildcardType.getLowerBounds()) {
        if (!isAssignableFrom(b, lowerBound)) {
          return false;
        }
      }
      for (Type upperBound : wildcardType.getUpperBounds()) {
        if (!isAssignableFrom(upperBound, b)) {
          return false;
        }
      }
      return true;
    }
    throw new IllegalStateException();
  }


  /**
   * Equivalent of {@link Class#isAssignableFrom(Class)} at the {@link Type}
   * level.
   */
  public static boolean isAssignableFrom(Type a, Type b) {
    if (a instanceof Class<?>) {
      Class<?> classA = (Class<?>) a;
      if (b instanceof Class<?>) {
        return classA.isAssignableFrom((Class<?>) b);
      } else if (b instanceof GenericArrayType) {
        return classA.isArray() && isAssignableFrom(
            classA.getComponentType(), ((GenericArrayType) b).getGenericComponentType());
      } else if (b instanceof ParameterizedType) {
        return classA.isAssignableFrom((Class<?>) ((ParameterizedType) b).getRawType());
      } else if (b instanceof TypeVariable<?>) {
        TypeVariable<?> typeVariableB = (TypeVariable<?>) b;
        for (Type upperBound : typeVariableB.getBounds()) {
          if (!isAssignableFrom(a, upperBound)) {
            return false;
          }
        }
        return true;
      } else if (b instanceof WildcardType) {
        WildcardType wildcardTypeB = (WildcardType) b;
        for (Type upperBound : wildcardTypeB.getUpperBounds()) {
          if (!isAssignableFrom(a, upperBound)) {
            return false;
          }
        }
        return true;
      }
    } else if (a instanceof GenericArrayType) {
      if (b instanceof GenericArrayType) {
        return isAssignableFrom(
            ((GenericArrayType) a).getGenericComponentType(),
            ((GenericArrayType) b).getGenericComponentType());
      }
    } else if (a instanceof ParameterizedType) {
      ParameterizedType parameterizedTypeA = (ParameterizedType) a;
      if (b instanceof Class<?>) {
        return isAssignableFrom(parameterizedTypeA.getRawType(), b);
      } else if (b instanceof ParameterizedType) {
        ParameterizedType parameterizedTypeB = (ParameterizedType) b;
        Type[] actualTypeArgumentsA = parameterizedTypeA.getActualTypeArguments();
        Type[] actualTypeArgumentsB = parameterizedTypeB.getActualTypeArguments();
        if (actualTypeArgumentsA.length != actualTypeArgumentsB.length) {
          return false;
        }
        for (int i = 0; i < actualTypeArgumentsA.length; i++) {
          if (!isInstance(actualTypeArgumentsA[i], actualTypeArgumentsB[i])) {
            return false;
          }
        }
        return isAssignableFrom(
            parameterizedTypeA.getRawType(),
            parameterizedTypeB.getRawType());
      }
    } else if (a instanceof TypeVariable<?>) {
      for (Type bound : ((TypeVariable<?>) a).getBounds()) {
        if (!isAssignableFrom(bound, b)) {
          return false;
        }
      }
      return true;
    } else if (a instanceof WildcardType) {
      WildcardType wildcardType = (WildcardType) a;
      Type[] lowerBounds = wildcardType.getLowerBounds();
      for (Type lowerBound : lowerBounds) {
        if (!isAssignableFrom(lowerBound, b)) {
          return false;
        }
      }
      return lowerBounds.length != 0;
    }
    return false;
  }

} public final class Unification {
  private Unification() {}

  public static Type getActualTypeArgument(
      Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
    if (superClass.getTypeParameters().length <= typeParameterIndex) {
      throw new IllegalArgumentException(format(
          "%s does not have a type parameter of index %s",
          superClass, typeParameterIndex));
    }

    /* Assume the hierarchy is
     *
     *   A extends B<Integer>
     *   B<T1> extends C<List<T1>>
     *   C<T2>
     *
     * and we are resolving for T2.
     */

    // 1. Compute the linear hierarchy.
    // e.g. the inverted list [C, B, A] containing ClassWithType
    List<ClassWithType> linearHierarchy = getLinearHierarchy(subClass, superClass, null);
    if (linearHierarchy == null) {
      throw new IllegalArgumentException(format(
          "%s does not have %s as super class", subClass, superClass));
    }

    // 2. We now group by pairs actual type arguments and type variables.
    // e.g. [(Integer, T1), (List<T1>, T2)]
    LinkedList<GenericTypeInstantiation> chain = groupInGenericTypeInstantiations(
        superClass.getTypeParameters()[typeParameterIndex],
        linearHierarchy);

    // 3. Unify, i.e. solve for the rightmost type variable.
    return unify(chain);
  }

  private static List<ClassWithType> getLinearHierarchy(
      Class<?> subClass, Class<?> superClass, ParameterizedType type) {
    List<ClassWithType> linearHierarchy;

    // interfaces (array will be empty if class implements none)
    Class<?>[] interfaces = subClass.getInterfaces();
    Type[] genericInterfaces = subClass.getGenericInterfaces();
    for (int i = 0; i < min(interfaces.length, genericInterfaces.length); i++) {
      if (interfaces[i].equals(superClass)) {
        return newArrayList(
            new ClassWithType(
                interfaces[i], castToParameterizedType(subClass, genericInterfaces[i])),
            new ClassWithType(subClass, type));
      } else if (genericInterfaces[i] instanceof ParameterizedType) {
        linearHierarchy = getLinearHierarchy(
            interfaces[i], superClass, (ParameterizedType) genericInterfaces[i]);
        if (linearHierarchy != null) {
          linearHierarchy.add(new ClassWithType(subClass, type));
          return linearHierarchy;
        }
      }
    }

    // superclass
    Class<?> superclass = subClass.getSuperclass();
    if (superclass == null) {
      return null;
    }
    Type genericSuperclass = subClass.getGenericSuperclass();
    if (superclass.equals(Object.class)) {
      return null;
    } else if (superclass.equals(superClass)) {
      return newArrayList(
            new ClassWithType(superclass, castToParameterizedType(subClass, genericSuperclass)),
            new ClassWithType(subClass, type));
    } else {
      linearHierarchy = getLinearHierarchy(superclass, superClass,
            genericSuperclass instanceof ParameterizedType ?
                (ParameterizedType) genericSuperclass : null);
      if (linearHierarchy !=null) {
        linearHierarchy.add(new ClassWithType(subClass, type));
      }
      return linearHierarchy;
    }
  }

  private static ParameterizedType castToParameterizedType(Class<?> subClass, Type type) {
    if (!(type instanceof ParameterizedType)) {
      throw new IllegalArgumentException(format(
          "%s does extend parametrically %s", subClass, type));
    }
    return (ParameterizedType) type;
  }

  private static LinkedList<GenericTypeInstantiation> groupInGenericTypeInstantiations(
      TypeVariable<?> targetTypeVariable, List<ClassWithType> linearHierarchy) {
    LinkedList<GenericTypeInstantiation> chain = new LinkedList<GenericTypeInstantiation>();
    int max = linearHierarchy.size() - 1;
    resolve: for (int i = 0; i < max; /* done in loop */) {
      final ClassWithType classWithType = linearHierarchy.get(i);
      TypeVariable<?>[] typeParameters = classWithType.clazz.getTypeParameters();
      for (int index = 0; index < typeParameters.length; index++) {
        if (targetTypeVariable.equals(typeParameters[index])) {
          Type actualTypeVariable = classWithType.type.getActualTypeArguments()[index];
          chain.addFirst(new GenericTypeInstantiation(
              actualTypeVariable,
              typeParameters[index]));

          // next
          i++;
          TypeVariable<?>[] potentialTargetTypeParameters = linearHierarchy.get(i).clazz.getTypeParameters();
          if (potentialTargetTypeParameters.length <= index) {
            return chain;
          }
          for (int j = 0; j < potentialTargetTypeParameters.length; j++) {
            if (actualTypeVariable.equals(potentialTargetTypeParameters[j])) {
              targetTypeVariable = potentialTargetTypeParameters[j];
              continue resolve;
            }
          }
          targetTypeVariable = potentialTargetTypeParameters[index];
          continue resolve;
        }
      }
      throw new IllegalStateException();
    }
    throw new IllegalStateException();
  }

  private static Type unify(LinkedList<GenericTypeInstantiation> chain) {
    Type unifiedType = chain.getLast().typeVariable;
    Map<TypeVariable<?>, Type> replacements = newHashMap();
    for (int i = chain.size() - 1; 0 <= i; i--) {
      GenericTypeInstantiation gti = chain.get(i);
      replacements.put(gti.typeVariable, gti.actualType);
      unifiedType = applyReplacements(replacements, unifiedType);
    }
    return unifiedType;
  }

  private static Type applyReplacements(
      Map<TypeVariable<?>, Type> replacements, Type unifiedType) {
    if (unifiedType instanceof TypeVariable<?>) {
      return replacements.get(unifiedType);
    } else if (unifiedType instanceof Class<?>) {
      return unifiedType;
    } else if (unifiedType instanceof ParameterizedType) {
      ParameterizedType parameterizedType = (ParameterizedType) unifiedType;
      return new ParameterizedTypeImpl(
          applyReplacements(replacements, parameterizedType.getRawType()),
          applyReplacements(replacements, parameterizedType.getActualTypeArguments()));
    }
    throw new IllegalStateException("other kinds of types not handled yet");
  }

  private static Type[] applyReplacements(
      Map<TypeVariable<?>, Type> replacements, Type[] types) {
    Type[] replacedTypes = new Type[types.length];
    for (int i = 0; i < types.length; i++) {
      replacedTypes[i] = applyReplacements(replacements, types[i]);
    }
    return replacedTypes;
  }

  private static class GenericTypeInstantiation {
    private final Type actualType;
    private final TypeVariable<?> typeVariable;
    private GenericTypeInstantiation(
        Type actualType, TypeVariable<?> typeVariable) {
      this.actualType = actualType;
      this.typeVariable = typeVariable;
    }
    @Override
    public String toString() {
      return format("(%s,%s)", actualType, typeVariable);
    }
  }

  private static class ClassWithType {
    private Class<?> clazz;
    private ParameterizedType type;
    private ClassWithType(Class<?> clazz, ParameterizedType type) {
      this.clazz = clazz;
      this.type = type;
    }
    @Override
    public String toString() {
      return type == null ? "-" : type.toString();
    }
  }

}
 static class AnalysisResult {
  Map<String, FormalParameter> assignments;
  String[] paramaterNames;
} static class FormalParameter implements JavaValue {
  private final int index;
  private final Class<?> kind;
  FormalParameter(int index, Class<?> kind) {
    this.index = index;
    this.kind = kind;
  }
  @Override
  public String toString() {
    return format("p%s", index);
  }
  int getIndex() {
    return index;
  }
  Class<?> getKind() {
    return kind;
  }
  @Override
  public boolean containsFormalParameter() {
    return true;
  }
}
import static com.kaching.platform.converters.CollectionOfElementsConverter.COLLECTION_KINDS;
import static com.kaching.platform.converters.InstantiatorErrors.cannotAnnotateOptionWithOptional;
import static com.kaching.platform.converters.InstantiatorErrors.cannotSpecifyDefaultValueAndConstant;
import static com.kaching.platform.converters.InstantiatorErrors.constantHasIncompatibleType;
import static com.kaching.platform.converters.InstantiatorErrors.constantIsNotStaticFinal;
import static com.kaching.platform.converters.InstantiatorErrors.enumHasAmbiguousNames;
import static com.kaching.platform.converters.InstantiatorErrors.illegalConstructor;
import static com.kaching.platform.converters.InstantiatorErrors.incorrectBoundForConverter;
import static com.kaching.platform.converters.InstantiatorErrors.incorrectDefaultValue;
import static com.kaching.platform.converters.InstantiatorErrors.moreThanOneConstructor;
import static com.kaching.platform.converters.InstantiatorErrors.moreThanOneConstructorWithInstantiate;
import static com.kaching.platform.converters.InstantiatorErrors.moreThanOneMatchingFunction;
import static com.kaching.platform.converters.InstantiatorErrors.noConverterForType;
import static com.kaching.platform.converters.InstantiatorErrors.noSuchField;
import static com.kaching.platform.converters.InstantiatorErrors.optionalLiteralParameterMustHaveDefault;
import static com.kaching.platform.converters.InstantiatorErrors.unableToGetField;
import static com.kaching.platform.converters.InstantiatorErrors.unableToInstantiate;
import static com.kaching.platform.converters.InstantiatorErrors.unableToResolveConstant;
import static com.kaching.platform.converters.InstantiatorErrors.unableToResolveFullyQualifiedConstant;
import static com.kaching.platform.converters.NativeConverters.C_BOOLEAN;
import static com.kaching.platform.converters.NativeConverters.C_BYTE;
import static com.kaching.platform.converters.NativeConverters.C_CHAR;
import static com.kaching.platform.converters.NativeConverters.C_DOUBLE;
import static com.kaching.platform.converters.NativeConverters.C_FLOAT;
import static com.kaching.platform.converters.NativeConverters.C_INT;
import static com.kaching.platform.converters.NativeConverters.C_LONG;
import static com.kaching.platform.converters.NativeConverters.C_SHORT;
import static com.kaching.platform.converters.NativeConverters.C_STRING;
import static com.kaching.platform.converters.Optional.VALUE_DEFAULT;
import static java.lang.String.format;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.inject.TypeLiteral;
import com.kaching.platform.common.Errors;
import com.kaching.platform.common.Option;
import com.kaching.platform.common.types.Types;
import com.kaching.platform.common.types.Unification;
import com.kaching.platform.converters.ConstructorAnalysis.AnalysisResult;
import com.kaching.platform.converters.ConstructorAnalysis.FormalParameter;
      // 4. base converters
      if (BASE_CONVERTERS.containsKey(targetClass)) {
        return Option.some(BASE_CONVERTERS.get(targetClass));
      }
      // 5. has <init>(Ljava/lang/String;)V;
      for (Converter<?> converter : createConverterUsingStringConstructor(targetClass)) {
        return Option.some(converter);
      }
      // 6. is an Enum
      if (Enum.class.isAssignableFrom(targetClass)) {
        try {
          return Option.some((Converter<?>) new EnumConverter(targetClass));
        } catch (IllegalArgumentException e) {
          enumHasAmbiguousNames(errors, targetClass);
        }
      }
    } else if (targetType instanceof ParameterizedType) {
      // 7. has <init>(Ljava/lang/String;)V;
      for (Converter<?> converter : createConverterUsingStringConstructor(
            (Class)((ParameterizedType) targetType).getRawType())) {
        return Option.some(converter);
      }
      // 8. Set, List, Collection
      ParameterizedType parameterizedTargetType = (ParameterizedType) targetType;
      if (COLLECTION_KINDS.containsKey(parameterizedTargetType.getRawType()) &&
          parameterizedTargetType.getActualTypeArguments().length == 1) {
        Option<? extends Converter<?>> maybeElementConverter = createConverter(
            parameterizedTargetType.getActualTypeArguments()[0]);
        if (maybeElementConverter.isDefined()) {
          return (Option) Option.some(new CollectionOfElementsConverter(
              parameterizedTargetType.getRawType(),
              maybeElementConverter.getOrThrow()));
        }
      } else {
        // TODO(pascal) provide more detailed errors such as "you need to
        // parameterize your list"
      }
    }

    if (sizeBefore == errors.size()) {
      noConverterForType(errors, targetType);
    }
    return Option.none();
  }

  @VisibleForTesting
  Field[] retrieveFieldsFromAssignment(
      int parametersCount, Map<String, FormalParameter> assignments) {
    Field[] fields = new Field[parametersCount];
    outer: for (Entry<String, FormalParameter> entry : assignments.entrySet()) {
      int parameterIndex = entry.getValue().getIndex();
      if (parameterIndex < 0 || fields.length <= parameterIndex) {
        throw new IllegalStateException(
            format("formal parameter out of bounds (index %s)", parameterIndex));
      }

      Field field = null;
      String fieldName = entry.getKey();
      Class<?> classSearched = klass;
      while (true) {
        try {
          field = classSearched.getDeclaredField(fieldName);
          field.setAccessible(true);
          fields[parameterIndex] = field;
          continue outer;
        } catch (SecurityException e) {
          unableToGetField(errors, fieldName, e);
          continue outer;
        } catch (NoSuchFieldException e) {
          if (classSearched.equals(Object.class)) {
            noSuchField(errors, fieldName);
            continue outer;
          } else {
            classSearched = classSearched.getSuperclass();
          }
        }
      }
    }
    return fields;
  }

  private Option<? extends Converter<?>> createConverterUsingConvertedBy(
      final Type targetType, Class<?> targetClass) {
    Annotation[] typeAnnotations = targetClass.getAnnotations();
    for (Annotation typeAnnotation : typeAnnotations) {
      if (typeAnnotation instanceof ConvertedBy) {
        Class<? extends Converter<?>> converterClass = ((ConvertedBy) typeAnnotation).value();
        for (Converter<?> converter : instantiateConverter(converterClass, targetType)) {
          return Option.some(converter);
        }
      }
    }
    return Option.none();
  }

  private Option<? extends Converter<?>> createConverterUsingStringConstructor(
      final Class<?> targetClass) {
    Constructor<?> stringConstructor;
    try {
      stringConstructor = targetClass.getDeclaredConstructor(String.class);
    } catch (SecurityException e) {
      // do proper exception handling, add this to errors
      throw new RuntimeException(e);
    } catch (NoSuchMethodException e) {
      // Not having a String constructor is an acceptable outcome.
      return Option.none();
    }
    return Option.some(new StringConstructorConverter<Object>(stringConstructor));
  }

  private Option<? extends Converter<?>> instantiateConverter(
      Class<? extends Converter<?>> converterClass, Type targetType) {
    try {
      Type producedType =
          Unification.getActualTypeArgument(converterClass, Converter.class, 0);
      if (Types.isInstance(producedType, targetType)) {
        Constructor<? extends Converter<?>> ctor = converterClass.getDeclaredConstructor();
        ctor.setAccessible(true);
        return Option.some(ctor.newInstance());
      } else {
        incorrectBoundForConverter(errors, targetType, converterClass, producedType);