static <T> InstantiatorImplFactory<T> createFactory(Errors errors, Class<T> klass) {
  return new InstantiatorImplFactory<T>(errors, klass);
} 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();
  }

}
import static com.google.common.collect.Lists.newArrayList;
import static com.kaching.platform.converters.InstantiatorImplFactory.createFactory;
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 org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.Constructor;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.kaching.platform.common.Errors;

            new Converter[] { C_STRING },
            null,
            new BitSet(),
            new BitSet(),
            null,
            null,
            null);
    try {
      instantiator.newInstance("first", "second");
      fail();
    } catch (IllegalArgumentException e) {
      assertEquals("wrong number of arguments", e.getMessage());
    }
  }

  @Test
  public void nullNotAllowedIsNotOptional() throws Exception {
    InstantiatorImpl<String> instantiator =
      new InstantiatorImpl<String>(
          String.class.getConstructor(String.class),
          new Converter[] { C_STRING },
          null,
          new BitSet(),
          new BitSet(),
          null,
          null,
          null);
    try {
      instantiator.newInstance((String) null);
      fail();
    } catch (IllegalArgumentException e) {
      assertEquals("parameter 1 is not optional but null was provided", e.getMessage());
    }
  }

  @Test
  public void converterCannotProduceNull() throws Exception {
    InstantiatorImpl<String> instantiator =
      new InstantiatorImpl<String>(
          String.class.getConstructor(String.class),
          new Converter[] { new ConverterOnlyProducesNull() },
          null,
          new BitSet(),
          new BitSet(),
          null,
          null,
          null);
    try {
      instantiator.newInstance("hello");
      fail();
    } catch (IllegalStateException e) {
      assertEquals(
          "converter class com.kaching.platform.converters.InstantiatorImplTest" +
          "$ConverterOnlyProducesNull produced a null value",
          e.getMessage());
    }
  }

  static class ConverterOnlyProducesNull implements Converter<String> {
    @Override public String toString(String value) { return null; }
    @Override public String fromString(String representation) { return null; }
  }

  @Test
  public void optionalArgument() throws Exception {
    BitSet optionality = new BitSet();
    optionality.set(0);
    WrappedString instance = new InstantiatorImpl<WrappedString>(
        WrappedString.class.getConstructor(String.class),
        new Converter[] { C_STRING },
        null,
        optionality,
        new BitSet(),
        null,
        null,
        null)
        .newInstance((String) null);
    assertNotNull(instance);
    assertNull(instance.string);
  }

  static class WrappedString {
    private final String string;
    public WrappedString(String string) {
      this.string = string;
    }
  }

  @Test
  public void optionalArgumentWithDefault() throws Exception {
    BitSet optionality = new BitSet();
    optionality.set(0);
    WrappedLong instance = new InstantiatorImpl<WrappedLong>(
        WrappedLong.class.getConstructor(Long.TYPE),
        new Converter[] { C_LONG },
        null,
        optionality,
        new BitSet(),
        new String[] { "403" },
        null,
        null)
        .newInstance((String) null);
    assertNotNull(instance);
    assertEquals(403L, instance.value);
  }

  static class WrappedLong {
    private final long value;
    public WrappedLong(long value) {
      this.value = value;
    }
  }

  @Test
  public void natives() throws Exception {
    Natives instance = new InstantiatorImpl<Natives>(
        Natives.class.getConstructor(
            Integer.TYPE, Double.TYPE, Short.TYPE, Character.TYPE,
            Long.TYPE, Boolean.TYPE, Float.TYPE, Byte.TYPE),
        new Converter[] {

          C_INT, C_DOUBLE, C_SHORT, C_CHAR,
