public static Object convertValue(String className, Object cleanValue, ClassLoader classLoader) {
        // "null" string is converted to null
        cleanValue = "null".equals(cleanValue) ? null : cleanValue;

        if (!isPrimitive(className) && cleanValue == null) {
            return null;
        }

        Class<?> clazz = loadClass(className, classLoader);

        // if it is not a String, it has to be an instance of the desired type
        if (!(cleanValue instanceof String)) {
            if (clazz.isInstance(cleanValue)) {
                return cleanValue;
            }
            throw new IllegalArgumentException(new StringBuilder().append("Object ").append(cleanValue)
                                                       .append(" is not a String or an instance of ").append(className).toString());
        }

        String value = (String) cleanValue;

        try {
            if (clazz.isAssignableFrom(String.class)) {
                return value;
            } else if (clazz.isAssignableFrom(BigDecimal.class)) {
                return parseBigDecimal(value);
            } else if (clazz.isAssignableFrom(BigInteger.class)) {
                return parseBigInteger(value);
            } else if (clazz.isAssignableFrom(Boolean.class) || clazz.isAssignableFrom(boolean.class)) {
                return parseBoolean(value);
            } else if (clazz.isAssignableFrom(Byte.class) || clazz.isAssignableFrom(byte.class)) {
                return Byte.parseByte(value);
            } else if (clazz.isAssignableFrom(Character.class) || clazz.isAssignableFrom(char.class)) {
                return parseChar(value);
            } else if (clazz.isAssignableFrom(Double.class) || clazz.isAssignableFrom(double.class)) {
                return Double.parseDouble(cleanStringForNumberParsing(value));
            } else if (clazz.isAssignableFrom(Float.class) || clazz.isAssignableFrom(float.class)) {
                return Float.parseFloat(cleanStringForNumberParsing(value));
            } else if (clazz.isAssignableFrom(Integer.class) || clazz.isAssignableFrom(int.class)) {
                return Integer.parseInt(cleanStringForNumberParsing(value));
            } else if (clazz.isAssignableFrom(LocalDate.class)) {
                return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE);
            } else if (clazz.isAssignableFrom(LocalDateTime.class)) {
                return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            } else if (clazz.isAssignableFrom(LocalTime.class)) {
                return LocalTime.parse(value, DateTimeFormatter.ISO_LOCAL_TIME);
            } else if (clazz.isAssignableFrom(Long.class) || clazz.isAssignableFrom(long.class)) {
                return Long.parseLong(cleanStringForNumberParsing(value));
            } else if (clazz.isAssignableFrom(Short.class) || clazz.isAssignableFrom(short.class)) {
                return Short.parseShort(cleanStringForNumberParsing(value));
            } else if (Enum.class.isAssignableFrom(clazz)) {
                return Enum.valueOf(((Class<? extends Enum>) clazz), value);
            }
        } catch (RuntimeException e) {
            throw new IllegalArgumentException(new StringBuilder().append("Impossible to parse '")
                                                       .append(value).append("' as ").append(className).append(" [")
                                                       .append(e.getMessage()).append("]").toString());
        }

        throw new IllegalArgumentException(new StringBuilder().append("Class ").append(className)
                                                   .append(" is not natively supported. Please use an MVEL expression" +
                                                                   " to use it.").toString());
    }
@Test
    public void convertValue_manyCases() {
        assertThat(convertValue(String.class.getCanonicalName(), "Test", classLoader)).isEqualTo("Test");
        assertThat(convertValue(BigDecimal.class.getCanonicalName(), "13.33", classLoader)).isEqualTo(BigDecimal.valueOf(13.33));
        assertThat(convertValue(BigDecimal.class.getCanonicalName(), "13", classLoader)).isEqualTo(BigDecimal.valueOf(13));
        assertThat(convertValue(BigDecimal.class.getCanonicalName(), "1,232,113.33", classLoader)).isEqualTo(BigDecimal.valueOf(1232113.33));
        assertThat(convertValue(BigDecimal.class.getCanonicalName(), "1232113.33", classLoader)).isEqualTo(BigDecimal.valueOf(1232113.33));
        assertThat(convertValue(BigInteger.class.getCanonicalName(), "13.33", classLoader)).isEqualTo(BigInteger.valueOf(13));
        assertThat(convertValue(BigInteger.class.getCanonicalName(), "13", classLoader)).isEqualTo(BigInteger.valueOf(13));
        assertThat(convertValue(BigInteger.class.getCanonicalName(), "1,232,113.33", classLoader)).isEqualTo(BigInteger.valueOf(1232113));
        assertThat(convertValue(BigInteger.class.getCanonicalName(), "1232113", classLoader)).isEqualTo(BigInteger.valueOf(1232113));
        assertThat(convertValue(boolean.class.getCanonicalName(), "false", classLoader)).isEqualTo(false);
        assertThat(convertValue(Boolean.class.getCanonicalName(), "true", classLoader)).isEqualTo(true);
        assertThat(convertValue(int.class.getCanonicalName(), "1", classLoader)).isEqualTo(1);
        assertThat(convertValue(Integer.class.getCanonicalName(), "1", classLoader)).isEqualTo(1);
        assertThat(convertValue(long.class.getCanonicalName(), "1", classLoader)).isEqualTo(1L);
        assertThat(convertValue(Long.class.getCanonicalName(), "1", classLoader)).isEqualTo(1L);
        assertThat(convertValue(double.class.getCanonicalName(), "1", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(Double.class.getCanonicalName(), "1", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(float.class.getCanonicalName(), "1", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(Float.class.getCanonicalName(), "1", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(double.class.getCanonicalName(), "1.0", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(Double.class.getCanonicalName(), "1.0", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(float.class.getCanonicalName(), "1.0", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(Float.class.getCanonicalName(), "1.0", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(double.class.getCanonicalName(), "1.0d", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(Double.class.getCanonicalName(), "1.0d", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(float.class.getCanonicalName(), "1.0f", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(Float.class.getCanonicalName(), "1.0f", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(double.class.getCanonicalName(), "1.0D", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(Double.class.getCanonicalName(), "1.0D", classLoader)).isEqualTo(1.0d);
        assertThat(convertValue(float.class.getCanonicalName(), "1.0F", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(Float.class.getCanonicalName(), "1.0F", classLoader)).isEqualTo(1.0f);
        assertThat(convertValue(char.class.getCanonicalName(), "a", classLoader)).isEqualTo('a');
        assertThat(convertValue(Character.class.getCanonicalName(), "a", classLoader)).isEqualTo('a');
        assertThat(convertValue(short.class.getCanonicalName(), "1", classLoader)).isEqualTo((short) 1);
        assertThat(convertValue(Short.class.getCanonicalName(), "1", classLoader)).isEqualTo((short) 1);
        assertThat(convertValue(byte.class.getCanonicalName(), Byte.toString("0".getBytes()[0]), classLoader)).isEqualTo("0".getBytes()[0]);
        assertThat(convertValue(Byte.class.getCanonicalName(), Byte.toString("0".getBytes()[0]), classLoader)).isEqualTo("0".getBytes()[0]);
        assertThat(convertValue(LocalDate.class.getCanonicalName(), "2018-05-20", classLoader)).isEqualTo(LocalDate.of(2018, 5, 20));
        assertThat(convertValue(LocalDateTime.class.getCanonicalName(), "2017-02-18T10:30", classLoader)).isEqualTo(LocalDateTime.of(2017, 2, 18, 10, 30));
        assertThat(convertValue(LocalDateTime.class.getCanonicalName(), "1982-04-04T00:20", classLoader)).isEqualTo(LocalDateTime.of(1982, 4, 4, 0, 20, 0));
        assertThat(convertValue(LocalDateTime.class.getCanonicalName(), "1982-10-13T02:09:00.999999999", classLoader)).isEqualTo(LocalDateTime.of(1982, 10, 13, 2, 9, 0, 999999999));
        assertThat(convertValue(LocalTime.class.getCanonicalName(), "01:09:00", classLoader)).isEqualTo(LocalTime.of(1, 9, 0));
        assertThat(convertValue(LocalTime.class.getCanonicalName(), "04:59:07.009999999", classLoader)).isEqualTo(LocalTime.of(4, 59, 07, 9999999));
        assertThat(convertValue(LocalTime.class.getCanonicalName(), "23:45", classLoader)).isEqualTo(LocalTime.of(23, 45));
        assertThat(convertValue(LocalTime.class.getCanonicalName(), "01:09:00", classLoader)).isEqualTo(LocalTime.of(1, 9, 0));
        assertThat(convertValue(LocalTime.class.getCanonicalName(), "04:59:07.009999999", classLoader)).isEqualTo(LocalTime.of(4, 59, 07, 9999999));
        assertThat(convertValue(EnumTest.class.getCanonicalName(), "FIRST", classLoader)).isEqualTo(EnumTest.FIRST);
        assertThat(convertValue(Float.class.getCanonicalName(), null, classLoader)).isNull();
    }